mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
Merge branch 'net-remove-rtnl-from-fib_seq_sum'
Eric Dumazet says: ==================== net: remove RTNL from fib_seq_sum() This series is inspired by a syzbot report showing rtnl contention and one thread blocked in: 7 locks held by syz-executor/10835: #0: ffff888033390420 (sb_writers#8){.+.+}-{0:0}, at: file_start_write include/linux/fs.h:2931 [inline] #0: ffff888033390420 (sb_writers#8){.+.+}-{0:0}, at: vfs_write+0x224/0xc90 fs/read_write.c:679 #1: ffff88806df6bc88 (&of->mutex){+.+.}-{3:3}, at: kernfs_fop_write_iter+0x1ea/0x500 fs/kernfs/file.c:325 #2: ffff888026fcf3c8 (kn->active#50){.+.+}-{0:0}, at: kernfs_fop_write_iter+0x20e/0x500 fs/kernfs/file.c:326 #3: ffffffff8f56f848 (nsim_bus_dev_list_lock){+.+.}-{3:3}, at: new_device_store+0x1b4/0x890 drivers/net/netdevsim/bus.c:166 #4: ffff88805e0140e8 (&dev->mutex){....}-{3:3}, at: device_lock include/linux/device.h:1014 [inline] #4: ffff88805e0140e8 (&dev->mutex){....}-{3:3}, at: __device_attach+0x8e/0x520 drivers/base/dd.c:1005 #5: ffff88805c5fb250 (&devlink->lock_key#55){+.+.}-{3:3}, at: nsim_drv_probe+0xcb/0xb80 drivers/net/netdevsim/dev.c:1534 #6: ffffffff8fcd1748 (rtnl_mutex){+.+.}-{3:3}, at: fib_seq_sum+0x31/0x290 net/core/fib_notifier.c:46 ==================== Link: https://patch.msgid.link/20241009184405.3752829-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
356d568fa9
|
|
@ -28,7 +28,7 @@ enum fib_event_type {
|
|||
struct fib_notifier_ops {
|
||||
int family;
|
||||
struct list_head list;
|
||||
unsigned int (*fib_seq_read)(struct net *net);
|
||||
unsigned int (*fib_seq_read)(const struct net *net);
|
||||
int (*fib_dump)(struct net *net, struct notifier_block *nb,
|
||||
struct netlink_ext_ack *extack);
|
||||
struct module *owner;
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ int fib_default_rule_add(struct fib_rules_ops *, u32 pref, u32 table);
|
|||
bool fib_rule_matchall(const struct fib_rule *rule);
|
||||
int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
|
||||
struct netlink_ext_ack *extack);
|
||||
unsigned int fib_rules_seq_read(struct net *net, int family);
|
||||
unsigned int fib_rules_seq_read(const struct net *net, int family);
|
||||
|
||||
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ struct fib6_table {
|
|||
struct fib6_node tb6_root;
|
||||
struct inet_peer_base tb6_peers;
|
||||
unsigned int flags;
|
||||
unsigned int fib_seq;
|
||||
unsigned int fib_seq; /* writes protected by rtnl_mutex */
|
||||
struct hlist_head tb6_gc_hlist; /* GC candidates */
|
||||
#define RT6_TABLE_HAS_DFLT_ROUTER BIT(0)
|
||||
};
|
||||
|
|
@ -563,7 +563,7 @@ int call_fib6_notifiers(struct net *net, enum fib_event_type event_type,
|
|||
int __net_init fib6_notifier_init(struct net *net);
|
||||
void __net_exit fib6_notifier_exit(struct net *net);
|
||||
|
||||
unsigned int fib6_tables_seq_read(struct net *net);
|
||||
unsigned int fib6_tables_seq_read(const struct net *net);
|
||||
int fib6_tables_dump(struct net *net, struct notifier_block *nb,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
|
|
@ -632,7 +632,7 @@ void fib6_rules_cleanup(void);
|
|||
bool fib6_rule_default(const struct fib_rule *rule);
|
||||
int fib6_rules_dump(struct net *net, struct notifier_block *nb,
|
||||
struct netlink_ext_ack *extack);
|
||||
unsigned int fib6_rules_seq_read(struct net *net);
|
||||
unsigned int fib6_rules_seq_read(const struct net *net);
|
||||
|
||||
static inline bool fib6_rules_early_flow_dissect(struct net *net,
|
||||
struct sk_buff *skb,
|
||||
|
|
@ -676,7 +676,7 @@ static inline int fib6_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline unsigned int fib6_rules_seq_read(struct net *net)
|
||||
static inline unsigned int fib6_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ static inline int fib4_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int fib4_rules_seq_read(struct net *net)
|
||||
static inline unsigned int fib4_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ static inline bool fib4_has_custom_rules(const struct net *net)
|
|||
bool fib4_rule_default(const struct fib_rule *rule);
|
||||
int fib4_rules_dump(struct net *net, struct notifier_block *nb,
|
||||
struct netlink_ext_ack *extack);
|
||||
unsigned int fib4_rules_seq_read(struct net *net);
|
||||
unsigned int fib4_rules_seq_read(const struct net *net);
|
||||
|
||||
static inline bool fib4_rules_early_flow_dissect(struct net *net,
|
||||
struct sk_buff *skb,
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ struct netns_ipv4 {
|
|||
#endif
|
||||
|
||||
struct fib_notifier_ops *notifier_ops;
|
||||
unsigned int fib_seq; /* protected by rtnl_mutex */
|
||||
unsigned int fib_seq; /* writes protected by rtnl_mutex */
|
||||
|
||||
struct fib_notifier_ops *ipmr_notifier_ops;
|
||||
unsigned int ipmr_seq; /* protected by rtnl_mutex */
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ static unsigned int fib_seq_sum(struct net *net)
|
|||
struct fib_notifier_ops *ops;
|
||||
unsigned int fib_seq = 0;
|
||||
|
||||
rtnl_lock();
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) {
|
||||
if (!try_module_get(ops->owner))
|
||||
|
|
@ -52,7 +51,6 @@ static unsigned int fib_seq_sum(struct net *net)
|
|||
module_put(ops->owner);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
rtnl_unlock();
|
||||
|
||||
return fib_seq;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,8 @@ static void notify_rule_change(int event, struct fib_rule *rule,
|
|||
struct fib_rules_ops *ops, struct nlmsghdr *nlh,
|
||||
u32 pid);
|
||||
|
||||
static struct fib_rules_ops *lookup_rules_ops(struct net *net, int family)
|
||||
static struct fib_rules_ops *lookup_rules_ops(const struct net *net,
|
||||
int family)
|
||||
{
|
||||
struct fib_rules_ops *ops;
|
||||
|
||||
|
|
@ -370,7 +371,9 @@ static int call_fib_rule_notifiers(struct net *net,
|
|||
.rule = rule,
|
||||
};
|
||||
|
||||
ops->fib_rules_seq++;
|
||||
ASSERT_RTNL();
|
||||
/* Paired with READ_ONCE() in fib_rules_seq() */
|
||||
WRITE_ONCE(ops->fib_rules_seq, ops->fib_rules_seq + 1);
|
||||
return call_fib_notifiers(net, event_type, &info.info);
|
||||
}
|
||||
|
||||
|
|
@ -397,17 +400,16 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(fib_rules_dump);
|
||||
|
||||
unsigned int fib_rules_seq_read(struct net *net, int family)
|
||||
unsigned int fib_rules_seq_read(const struct net *net, int family)
|
||||
{
|
||||
unsigned int fib_rules_seq;
|
||||
struct fib_rules_ops *ops;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
ops = lookup_rules_ops(net, family);
|
||||
if (!ops)
|
||||
return 0;
|
||||
fib_rules_seq = ops->fib_rules_seq;
|
||||
/* Paired with WRITE_ONCE() in call_fib_rule_notifiers() */
|
||||
fib_rules_seq = READ_ONCE(ops->fib_rules_seq);
|
||||
rules_ops_put(ops);
|
||||
|
||||
return fib_rules_seq;
|
||||
|
|
|
|||
|
|
@ -22,15 +22,15 @@ int call_fib4_notifiers(struct net *net, enum fib_event_type event_type,
|
|||
ASSERT_RTNL();
|
||||
|
||||
info->family = AF_INET;
|
||||
net->ipv4.fib_seq++;
|
||||
/* Paired with READ_ONCE() in fib4_seq_read() */
|
||||
WRITE_ONCE(net->ipv4.fib_seq, net->ipv4.fib_seq + 1);
|
||||
return call_fib_notifiers(net, event_type, info);
|
||||
}
|
||||
|
||||
static unsigned int fib4_seq_read(struct net *net)
|
||||
static unsigned int fib4_seq_read(const struct net *net)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
return net->ipv4.fib_seq + fib4_rules_seq_read(net);
|
||||
/* Paired with WRITE_ONCE() in call_fib4_notifiers() */
|
||||
return READ_ONCE(net->ipv4.fib_seq) + fib4_rules_seq_read(net);
|
||||
}
|
||||
|
||||
static int fib4_dump(struct net *net, struct notifier_block *nb,
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ int fib4_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
return fib_rules_dump(net, nb, AF_INET, extack);
|
||||
}
|
||||
|
||||
unsigned int fib4_rules_seq_read(struct net *net)
|
||||
unsigned int fib4_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return fib_rules_seq_read(net, AF_INET);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ static int ipmr_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
return fib_rules_dump(net, nb, RTNL_FAMILY_IPMR, extack);
|
||||
}
|
||||
|
||||
static unsigned int ipmr_rules_seq_read(struct net *net)
|
||||
static unsigned int ipmr_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return fib_rules_seq_read(net, RTNL_FAMILY_IPMR);
|
||||
}
|
||||
|
|
@ -346,7 +346,7 @@ static int ipmr_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ipmr_rules_seq_read(struct net *net)
|
||||
static unsigned int ipmr_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3035,11 +3035,9 @@ static const struct net_protocol pim_protocol = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static unsigned int ipmr_seq_read(struct net *net)
|
||||
static unsigned int ipmr_seq_read(const struct net *net)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
return net->ipv4.ipmr_seq + ipmr_rules_seq_read(net);
|
||||
return READ_ONCE(net->ipv4.ipmr_seq) + ipmr_rules_seq_read(net);
|
||||
}
|
||||
|
||||
static int ipmr_dump(struct net *net, struct notifier_block *nb,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ int call_fib6_notifiers(struct net *net, enum fib_event_type event_type,
|
|||
return call_fib_notifiers(net, event_type, info);
|
||||
}
|
||||
|
||||
static unsigned int fib6_seq_read(struct net *net)
|
||||
static unsigned int fib6_seq_read(const struct net *net)
|
||||
{
|
||||
return fib6_tables_seq_read(net) + fib6_rules_seq_read(net);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ int fib6_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
return fib_rules_dump(net, nb, AF_INET6, extack);
|
||||
}
|
||||
|
||||
unsigned int fib6_rules_seq_read(struct net *net)
|
||||
unsigned int fib6_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return fib_rules_seq_read(net, AF_INET6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -345,17 +345,17 @@ static void __net_init fib6_tables_init(struct net *net)
|
|||
|
||||
#endif
|
||||
|
||||
unsigned int fib6_tables_seq_read(struct net *net)
|
||||
unsigned int fib6_tables_seq_read(const struct net *net)
|
||||
{
|
||||
unsigned int h, fib_seq = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
|
||||
struct hlist_head *head = &net->ipv6.fib_table_hash[h];
|
||||
struct fib6_table *tb;
|
||||
const struct hlist_head *head = &net->ipv6.fib_table_hash[h];
|
||||
const struct fib6_table *tb;
|
||||
|
||||
hlist_for_each_entry_rcu(tb, head, tb6_hlist)
|
||||
fib_seq += tb->fib_seq;
|
||||
fib_seq += READ_ONCE(tb->fib_seq);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
@ -400,7 +400,7 @@ int call_fib6_entry_notifiers(struct net *net,
|
|||
.rt = rt,
|
||||
};
|
||||
|
||||
rt->fib6_table->fib_seq++;
|
||||
WRITE_ONCE(rt->fib6_table->fib_seq, rt->fib6_table->fib_seq + 1);
|
||||
return call_fib6_notifiers(net, event_type, &info.info);
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +416,7 @@ int call_fib6_multipath_entry_notifiers(struct net *net,
|
|||
.nsiblings = nsiblings,
|
||||
};
|
||||
|
||||
rt->fib6_table->fib_seq++;
|
||||
WRITE_ONCE(rt->fib6_table->fib_seq, rt->fib6_table->fib_seq + 1);
|
||||
return call_fib6_notifiers(net, event_type, &info.info);
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +427,7 @@ int call_fib6_entry_notifiers_replace(struct net *net, struct fib6_info *rt)
|
|||
.nsiblings = rt->fib6_nsiblings,
|
||||
};
|
||||
|
||||
rt->fib6_table->fib_seq++;
|
||||
WRITE_ONCE(rt->fib6_table->fib_seq, rt->fib6_table->fib_seq + 1);
|
||||
return call_fib6_notifiers(net, FIB_EVENT_ENTRY_REPLACE, &info.info);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR, extack);
|
||||
}
|
||||
|
||||
static unsigned int ip6mr_rules_seq_read(struct net *net)
|
||||
static unsigned int ip6mr_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return fib_rules_seq_read(net, RTNL_FAMILY_IP6MR);
|
||||
}
|
||||
|
|
@ -335,7 +335,7 @@ static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ip6mr_rules_seq_read(struct net *net)
|
||||
static unsigned int ip6mr_rules_seq_read(const struct net *net)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1260,11 +1260,9 @@ static int ip6mr_device_event(struct notifier_block *this,
|
|||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static unsigned int ip6mr_seq_read(struct net *net)
|
||||
static unsigned int ip6mr_seq_read(const struct net *net)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net);
|
||||
return READ_ONCE(net->ipv6.ipmr_seq) + ip6mr_rules_seq_read(net);
|
||||
}
|
||||
|
||||
static int ip6mr_dump(struct net *net, struct notifier_block *nb,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user