From c66d93e68728cfb5f40b40d0f24129d7768faf43 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Sat, 26 Sep 2026 03:33:52 +0000 Subject: [PATCH] ipv6: Remove FIB6_EXCEPTION_BUCKET_FLUSHED. The FIB6_EXCEPTION_BUCKET_FLUSHED logic has been dead since added. Commit 0346ec2f080b ("ipv6: Prevent rt6_insert_exception() for dying fib6_info.") restored the original race protection in rt6_insert_exception() by reusing fib6_info.fib6_destroying. The flag now prevents two races for per-cpu and exception routes. Let's remove FIB6_EXCEPTION_BUCKET_FLUSHED and set fib6_destroying in fib6_purge_rt(). Signed-off-by: Kuniyuki Iwashima Reviewed-by: Ido Schimmel Link: https://patch.msgid.link/20260926033355.3295550-1-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/ip6_fib.c | 14 +++++++------- net/ipv6/route.c | 45 --------------------------------------------- 2 files changed, 7 insertions(+), 52 deletions(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 9ff761962b45..0dc6ebee6e56 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1019,12 +1019,6 @@ static int fib6_nh_drop_pcpu_from(struct fib6_nh *nh, void *_arg) static void fib6_drop_pcpu_from(struct fib6_info *f6i) { - /* Make sure rt6_make_pcpu_route() wont add other percpu routes - * while we are cleaning them here. - */ - f6i->fib6_destroying = 1; - mb(); /* paired with the cmpxchg() in rt6_make_pcpu_route() */ - if (f6i->nh) { rcu_read_lock(); nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_drop_pcpu_from, f6i); @@ -1042,7 +1036,13 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn, { struct fib6_table *table = rt->fib6_table; - /* Flush all cached dst in exception table */ + /* Make sure rt6_make_pcpu_route() / rt6_insert_exception() + * will not add other percpu / exception routes after cleaning + * them up in __fib6_drop_pcpu_from() / rt6_flush_exceptions(). + */ + rt->fib6_destroying = 1; + mb(); /* paired with the cmpxchg() in rt6_make_pcpu_route() */ + fib6_drop_pcpu_from(rt); rt6_flush_exceptions(rt); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 475ced827ec5..a76869ff87cd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1663,13 +1663,6 @@ static unsigned int fib6_mtu(const struct fib6_result *res) return mtu - lwtunnel_headroom(nh->fib_nh_lws, mtu); } -#define FIB6_EXCEPTION_BUCKET_FLUSHED 0x1UL - -/* used when the flushed bit is not relevant, only access to the bucket - * (ie., all bucket users except rt6_insert_exception); - * - * called under rcu lock; sometimes called with rt6_exception_lock held - */ static struct rt6_exception_bucket *fib6_nh_get_excptn_bucket(const struct fib6_nh *nh, spinlock_t *lock) @@ -1682,40 +1675,9 @@ struct rt6_exception_bucket *fib6_nh_get_excptn_bucket(const struct fib6_nh *nh, else bucket = rcu_dereference(nh->rt6i_exception_bucket); - /* remove bucket flushed bit if set */ - if (bucket) { - unsigned long p = (unsigned long)bucket; - - p &= ~FIB6_EXCEPTION_BUCKET_FLUSHED; - bucket = (struct rt6_exception_bucket *)p; - } - return bucket; } -static bool fib6_nh_excptn_bucket_flushed(struct rt6_exception_bucket *bucket) -{ - unsigned long p = (unsigned long)bucket; - - return !!(p & FIB6_EXCEPTION_BUCKET_FLUSHED); -} - -/* called with rt6_exception_lock held */ -static void fib6_nh_excptn_bucket_set_flushed(struct fib6_nh *nh, - spinlock_t *lock) -{ - struct rt6_exception_bucket *bucket; - unsigned long p; - - bucket = rcu_dereference_protected(nh->rt6i_exception_bucket, - lockdep_is_held(lock)); - - p = (unsigned long)bucket; - p |= FIB6_EXCEPTION_BUCKET_FLUSHED; - bucket = (struct rt6_exception_bucket *)p; - rcu_assign_pointer(nh->rt6i_exception_bucket, bucket); -} - static int rt6_insert_exception(struct rt6_info *nrt, const struct fib6_result *res) { @@ -1745,9 +1707,6 @@ static int rt6_insert_exception(struct rt6_info *nrt, goto out; } rcu_assign_pointer(nh->rt6i_exception_bucket, bucket); - } else if (fib6_nh_excptn_bucket_flushed(bucket)) { - err = -EINVAL; - goto out; } #ifdef CONFIG_IPV6_SUBTREES @@ -1818,10 +1777,6 @@ static void fib6_nh_flush_exceptions(struct fib6_nh *nh, struct fib6_info *from) if (!bucket) goto out; - /* Prevent rt6_insert_exception() to recreate the bucket list */ - if (!from) - fib6_nh_excptn_bucket_set_flushed(nh, &rt6_exception_lock); - for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) { hlist_for_each_entry_safe(rt6_ex, tmp, &bucket->chain, hlist) { if (!from ||