mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-21 14:39:30 -04:00
ipv4: fib: Drop RTNL annotation for net->ipv4.fib_table_hash[].
fib_newrule() will drop RTNL except for the first IPv4 rule.
net->ipv4.fib_table_hash[] will be read with no protection,
but this is fine because fib_table is not destroyed until
netns dismantle except for the merged main/local table.
fib_unmerge() will continue to be called under RTNL, so other
readers (fib_flush() and fib_info_notify_update()) just have
to care about the concurrent hlist_add().
IPv6 and IPMR/IP6MR also take this strategy and use RCU helpers
to avoid data race against concurrent hlist_add().
Let's not use lockdep_rtnl_is_held() and rcu_dereference_rtnl()
for net->ipv4.fib_table_hash[].
Note that commit a7e5353123 ("fib_trie: Make fib_table rcu
safe") started to use the _safe version in fib_flush(), but it
is not needed thanks to RTNL.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260629181226.1929658-5-kuniyu@google.com
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
committed by
Paolo Abeni
parent
4b8f5c974d
commit
763a943710
@@ -302,7 +302,8 @@ static inline struct fib_table *fib_get_table(struct net *net, u32 id)
|
||||
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] :
|
||||
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX];
|
||||
|
||||
tb_hlist = rcu_dereference_rtnl(hlist_first_rcu(ptr));
|
||||
/* Only fib4_rules_init() adds fib_table. */
|
||||
tb_hlist = rcu_dereference_protected(hlist_first_rcu(ptr), true);
|
||||
|
||||
return hlist_entry(tb_hlist, struct fib_table, tb_hlist);
|
||||
}
|
||||
|
||||
@@ -126,24 +126,28 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fib_new_table);
|
||||
|
||||
/* caller must hold either rtnl or rcu read lock */
|
||||
struct fib_table *fib_get_table(struct net *net, u32 id)
|
||||
{
|
||||
struct fib_table *tb;
|
||||
struct fib_table *tb = NULL;
|
||||
struct hlist_head *head;
|
||||
unsigned int h;
|
||||
|
||||
if (id == 0)
|
||||
id = RT_TABLE_MAIN;
|
||||
h = id & (FIB_TABLE_HASHSZ - 1);
|
||||
|
||||
head = &net->ipv4.fib_table_hash[h];
|
||||
hlist_for_each_entry_rcu(tb, head, tb_hlist,
|
||||
lockdep_rtnl_is_held()) {
|
||||
|
||||
/* fib_table is not destroyed until ip_fib_net_exit()
|
||||
* except for the merged main/local table.
|
||||
* fib_unmerge() is called under RTNL, so other readers
|
||||
* under RTNL (e.g. fib_flush(), fib_info_notify_update())
|
||||
* can safely traverse the list with rcu_dereference_raw().
|
||||
*/
|
||||
hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
|
||||
if (tb->tb_id == id)
|
||||
return tb;
|
||||
}
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
return tb;
|
||||
}
|
||||
#endif /* CONFIG_IP_MULTIPLE_TABLES */
|
||||
|
||||
@@ -206,10 +210,9 @@ void fib_flush(struct net *net)
|
||||
|
||||
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
|
||||
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
|
||||
struct hlist_node *tmp;
|
||||
struct fib_table *tb;
|
||||
|
||||
hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
|
||||
hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
|
||||
flushed += fib_table_flush(net, tb, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -2137,8 +2137,7 @@ void fib_info_notify_update(struct net *net, struct nl_info *info)
|
||||
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
|
||||
struct fib_table *tb;
|
||||
|
||||
hlist_for_each_entry_rcu(tb, head, tb_hlist,
|
||||
lockdep_rtnl_is_held())
|
||||
hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
|
||||
__fib_info_notify_update(net, tb, info);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user