mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
Merge branch 'ip-fix-route-leak-and-unregister_netdevice-stuck'
Kuniyuki Iwashima says:
====================
ip: Fix route leak and unregister_netdevice() stuck.
Jason Zhang fed commit 0346ec2f08 ("ipv6: Prevent
rt6_insert_exception() for dying fib6_info.") to LLM to
find tricks to cause the same symptom:
unregister_netdevice: waiting for gre6 to become free. Usage count = 4
ref_tracker: netdev@000000009652f190 has 1/3 users at
dst_alloc+0x14b/0x490
ip6_rt_cache_alloc+0x27b/0x670
__ip6_rt_update_pmtu+0x572/0x850
This series treats them.
====================
Link: https://patch.msgid.link/20261101064418.2055158-1-kuniyu@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
58fa96691c
|
|
@ -2494,6 +2494,8 @@ ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
|
||||
if (unlikely(!rt_cache_route(nhc, rth)))
|
||||
rt_add_uncached_list(rth);
|
||||
} else {
|
||||
rt_add_uncached_list(rth);
|
||||
}
|
||||
skb_dst_set(skb, &rth->dst);
|
||||
reason = SKB_NOT_DROPPED_YET;
|
||||
|
|
|
|||
|
|
@ -179,12 +179,20 @@ void rt6_uncached_list_flush_dev(struct net_device *dev)
|
|||
list_for_each_entry_safe(rt, safe, &ul->head, dst.rt_uncached) {
|
||||
struct inet6_dev *rt_idev = rt->rt6i_idev;
|
||||
struct net_device *rt_dev = rt->dst.dev;
|
||||
struct fib6_info *from;
|
||||
bool release_fib;
|
||||
|
||||
rcu_read_lock();
|
||||
from = rcu_dereference(rt->from);
|
||||
release_fib = from && from->fib6_destroying;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (rt_idev &&
|
||||
(dev ? rt_idev->dev == dev :
|
||||
READ_ONCE(rt_idev->dev->reg_state) == NETREG_UNREGISTERED)) {
|
||||
rt->rt6i_idev = in6_dev_get(blackhole_netdev);
|
||||
in6_dev_put(rt_idev);
|
||||
release_fib = true;
|
||||
}
|
||||
|
||||
if (dev ? rt_dev == dev :
|
||||
|
|
@ -193,6 +201,12 @@ void rt6_uncached_list_flush_dev(struct net_device *dev)
|
|||
netdev_ref_replace(rt_dev, blackhole_netdev,
|
||||
&rt->dst.dev_tracker,
|
||||
GFP_ATOMIC);
|
||||
release_fib = true;
|
||||
}
|
||||
|
||||
if (release_fib) {
|
||||
from = unrcu_pointer(xchg(&rt->from, NULL));
|
||||
fib6_info_release(from);
|
||||
}
|
||||
|
||||
if (rt->dst.dev == blackhole_netdev &&
|
||||
|
|
@ -3701,9 +3715,10 @@ void fib6_nh_release(struct fib6_nh *fib6_nh)
|
|||
{
|
||||
struct rt6_exception_bucket *bucket;
|
||||
|
||||
fib6_nh_release_dsts(fib6_nh);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
fib6_nh_flush_exceptions(fib6_nh, NULL);
|
||||
bucket = fib6_nh_get_excptn_bucket(fib6_nh, NULL);
|
||||
if (bucket) {
|
||||
rcu_assign_pointer(fib6_nh->rt6i_exception_bucket, NULL);
|
||||
|
|
@ -3712,7 +3727,6 @@ void fib6_nh_release(struct fib6_nh *fib6_nh)
|
|||
|
||||
rcu_read_unlock();
|
||||
|
||||
fib6_nh_release_dsts(fib6_nh);
|
||||
free_percpu(fib6_nh->rt6i_pcpu);
|
||||
|
||||
fib_nh_common_release(&fib6_nh->nh_common);
|
||||
|
|
@ -3722,6 +3736,8 @@ void fib6_nh_release_dsts(struct fib6_nh *fib6_nh)
|
|||
{
|
||||
int cpu;
|
||||
|
||||
fib6_nh_flush_exceptions(fib6_nh, NULL);
|
||||
|
||||
if (!fib6_nh->rt6i_pcpu)
|
||||
return;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user