From: David Ahern <dsah...@gmail.com> Move the existing pcpu walk in fib6_drop_pcpu_from to a new helper, __fib6_drop_pcpu_from, that can be invoked per fib6_nh with a reference to the from entries that need to be evicted. If the passed in from is non-NULL then only entries associated with that fib6_info are removed (fib entry is deleted); if the from is NULL are entries are flushed (nexthop is deleted).
For fib6_info entries with builtin fib6_nh (ie., current code) there is no change in behavior. Signed-off-by: David Ahern <dsah...@gmail.com> --- net/ipv6/ip6_fib.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 793830b2965d..aaffe4a653d8 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -874,10 +874,10 @@ static struct fib6_node *fib6_add_1(struct net *net, return ln; } -static void fib6_drop_pcpu_from(struct fib6_info *f6i, - const struct fib6_table *table) +static void __fib6_drop_pcpu_from(struct fib6_nh *fib6_nh, + const struct fib6_info *from, + const struct fib6_table *table) { - struct fib6_nh *fib6_nh = &f6i->fib6_nh; int cpu; if (!rcu_access_pointer(fib6_nh->rt6i_pcpu)) @@ -892,17 +892,27 @@ static void fib6_drop_pcpu_from(struct fib6_info *f6i, ppcpu_rt = per_cpu_ptr(fib6_nh->rt6i_pcpu, cpu); pcpu_rt = *ppcpu_rt; - if (pcpu_rt) { - struct fib6_info *from; + if (pcpu_rt && + (!from || rcu_access_pointer(pcpu_rt->from) == from)) { + struct fib6_info *pfrom; - from = rcu_dereference_protected(pcpu_rt->from, + pfrom = rcu_dereference_protected(pcpu_rt->from, lockdep_is_held(&table->tb6_lock)); rcu_assign_pointer(pcpu_rt->from, NULL); - fib6_info_release(from); + fib6_info_release(pfrom); } } } +static void fib6_drop_pcpu_from(struct fib6_info *f6i, + const struct fib6_table *table) +{ + struct fib6_nh *fib6_nh; + + fib6_nh = &f6i->fib6_nh; + __fib6_drop_pcpu_from(fib6_nh, f6i, table); +} + static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn, struct net *net) { @@ -930,8 +940,7 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn, lockdep_is_held(&table->tb6_lock)); } - if (rt->fib6_nh.rt6i_pcpu) - fib6_drop_pcpu_from(rt, table); + fib6_drop_pcpu_from(rt, table); } } -- 2.11.0