Skip to content

Commit 356d568

Browse files
committed
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>
2 parents d677aeb + 2698acd commit 356d568

14 files changed

Lines changed: 40 additions & 44 deletions

File tree

include/net/fib_notifier.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ enum fib_event_type {
2828
struct fib_notifier_ops {
2929
int family;
3030
struct list_head list;
31-
unsigned int (*fib_seq_read)(struct net *net);
31+
unsigned int (*fib_seq_read)(const struct net *net);
3232
int (*fib_dump)(struct net *net, struct notifier_block *nb,
3333
struct netlink_ext_ack *extack);
3434
struct module *owner;

include/net/fib_rules.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ int fib_default_rule_add(struct fib_rules_ops *, u32 pref, u32 table);
176176
bool fib_rule_matchall(const struct fib_rule *rule);
177177
int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
178178
struct netlink_ext_ack *extack);
179-
unsigned int fib_rules_seq_read(struct net *net, int family);
179+
unsigned int fib_rules_seq_read(const struct net *net, int family);
180180

181181
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
182182
struct netlink_ext_ack *extack);

include/net/ip6_fib.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ struct fib6_table {
394394
struct fib6_node tb6_root;
395395
struct inet_peer_base tb6_peers;
396396
unsigned int flags;
397-
unsigned int fib_seq;
397+
unsigned int fib_seq; /* writes protected by rtnl_mutex */
398398
struct hlist_head tb6_gc_hlist; /* GC candidates */
399399
#define RT6_TABLE_HAS_DFLT_ROUTER BIT(0)
400400
};
@@ -563,7 +563,7 @@ int call_fib6_notifiers(struct net *net, enum fib_event_type event_type,
563563
int __net_init fib6_notifier_init(struct net *net);
564564
void __net_exit fib6_notifier_exit(struct net *net);
565565

566-
unsigned int fib6_tables_seq_read(struct net *net);
566+
unsigned int fib6_tables_seq_read(const struct net *net);
567567
int fib6_tables_dump(struct net *net, struct notifier_block *nb,
568568
struct netlink_ext_ack *extack);
569569

@@ -632,7 +632,7 @@ void fib6_rules_cleanup(void);
632632
bool fib6_rule_default(const struct fib_rule *rule);
633633
int fib6_rules_dump(struct net *net, struct notifier_block *nb,
634634
struct netlink_ext_ack *extack);
635-
unsigned int fib6_rules_seq_read(struct net *net);
635+
unsigned int fib6_rules_seq_read(const struct net *net);
636636

637637
static inline bool fib6_rules_early_flow_dissect(struct net *net,
638638
struct sk_buff *skb,
@@ -676,7 +676,7 @@ static inline int fib6_rules_dump(struct net *net, struct notifier_block *nb,
676676
{
677677
return 0;
678678
}
679-
static inline unsigned int fib6_rules_seq_read(struct net *net)
679+
static inline unsigned int fib6_rules_seq_read(const struct net *net)
680680
{
681681
return 0;
682682
}

include/net/ip_fib.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ static inline int fib4_rules_dump(struct net *net, struct notifier_block *nb,
347347
return 0;
348348
}
349349

350-
static inline unsigned int fib4_rules_seq_read(struct net *net)
350+
static inline unsigned int fib4_rules_seq_read(const struct net *net)
351351
{
352352
return 0;
353353
}
@@ -411,7 +411,7 @@ static inline bool fib4_has_custom_rules(const struct net *net)
411411
bool fib4_rule_default(const struct fib_rule *rule);
412412
int fib4_rules_dump(struct net *net, struct notifier_block *nb,
413413
struct netlink_ext_ack *extack);
414-
unsigned int fib4_rules_seq_read(struct net *net);
414+
unsigned int fib4_rules_seq_read(const struct net *net);
415415

416416
static inline bool fib4_rules_early_flow_dissect(struct net *net,
417417
struct sk_buff *skb,

include/net/netns/ipv4.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ struct netns_ipv4 {
262262
#endif
263263

264264
struct fib_notifier_ops *notifier_ops;
265-
unsigned int fib_seq; /* protected by rtnl_mutex */
265+
unsigned int fib_seq; /* writes protected by rtnl_mutex */
266266

267267
struct fib_notifier_ops *ipmr_notifier_ops;
268268
unsigned int ipmr_seq; /* protected by rtnl_mutex */

net/core/fib_notifier.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ static unsigned int fib_seq_sum(struct net *net)
4343
struct fib_notifier_ops *ops;
4444
unsigned int fib_seq = 0;
4545

46-
rtnl_lock();
4746
rcu_read_lock();
4847
list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) {
4948
if (!try_module_get(ops->owner))
@@ -52,7 +51,6 @@ static unsigned int fib_seq_sum(struct net *net)
5251
module_put(ops->owner);
5352
}
5453
rcu_read_unlock();
55-
rtnl_unlock();
5654

5755
return fib_seq;
5856
}

net/core/fib_rules.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ static void notify_rule_change(int event, struct fib_rule *rule,
101101
struct fib_rules_ops *ops, struct nlmsghdr *nlh,
102102
u32 pid);
103103

104-
static struct fib_rules_ops *lookup_rules_ops(struct net *net, int family)
104+
static struct fib_rules_ops *lookup_rules_ops(const struct net *net,
105+
int family)
105106
{
106107
struct fib_rules_ops *ops;
107108

@@ -370,7 +371,9 @@ static int call_fib_rule_notifiers(struct net *net,
370371
.rule = rule,
371372
};
372373

373-
ops->fib_rules_seq++;
374+
ASSERT_RTNL();
375+
/* Paired with READ_ONCE() in fib_rules_seq() */
376+
WRITE_ONCE(ops->fib_rules_seq, ops->fib_rules_seq + 1);
374377
return call_fib_notifiers(net, event_type, &info.info);
375378
}
376379

@@ -397,17 +400,16 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
397400
}
398401
EXPORT_SYMBOL_GPL(fib_rules_dump);
399402

400-
unsigned int fib_rules_seq_read(struct net *net, int family)
403+
unsigned int fib_rules_seq_read(const struct net *net, int family)
401404
{
402405
unsigned int fib_rules_seq;
403406
struct fib_rules_ops *ops;
404407

405-
ASSERT_RTNL();
406-
407408
ops = lookup_rules_ops(net, family);
408409
if (!ops)
409410
return 0;
410-
fib_rules_seq = ops->fib_rules_seq;
411+
/* Paired with WRITE_ONCE() in call_fib_rule_notifiers() */
412+
fib_rules_seq = READ_ONCE(ops->fib_rules_seq);
411413
rules_ops_put(ops);
412414

413415
return fib_rules_seq;

net/ipv4/fib_notifier.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ int call_fib4_notifiers(struct net *net, enum fib_event_type event_type,
2222
ASSERT_RTNL();
2323

2424
info->family = AF_INET;
25-
net->ipv4.fib_seq++;
25+
/* Paired with READ_ONCE() in fib4_seq_read() */
26+
WRITE_ONCE(net->ipv4.fib_seq, net->ipv4.fib_seq + 1);
2627
return call_fib_notifiers(net, event_type, info);
2728
}
2829

29-
static unsigned int fib4_seq_read(struct net *net)
30+
static unsigned int fib4_seq_read(const struct net *net)
3031
{
31-
ASSERT_RTNL();
32-
33-
return net->ipv4.fib_seq + fib4_rules_seq_read(net);
32+
/* Paired with WRITE_ONCE() in call_fib4_notifiers() */
33+
return READ_ONCE(net->ipv4.fib_seq) + fib4_rules_seq_read(net);
3434
}
3535

3636
static int fib4_dump(struct net *net, struct notifier_block *nb,

net/ipv4/fib_rules.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ int fib4_rules_dump(struct net *net, struct notifier_block *nb,
7474
return fib_rules_dump(net, nb, AF_INET, extack);
7575
}
7676

77-
unsigned int fib4_rules_seq_read(struct net *net)
77+
unsigned int fib4_rules_seq_read(const struct net *net)
7878
{
7979
return fib_rules_seq_read(net, AF_INET);
8080
}

net/ipv4/ipmr.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ static int ipmr_rules_dump(struct net *net, struct notifier_block *nb,
288288
return fib_rules_dump(net, nb, RTNL_FAMILY_IPMR, extack);
289289
}
290290

291-
static unsigned int ipmr_rules_seq_read(struct net *net)
291+
static unsigned int ipmr_rules_seq_read(const struct net *net)
292292
{
293293
return fib_rules_seq_read(net, RTNL_FAMILY_IPMR);
294294
}
@@ -346,7 +346,7 @@ static int ipmr_rules_dump(struct net *net, struct notifier_block *nb,
346346
return 0;
347347
}
348348

349-
static unsigned int ipmr_rules_seq_read(struct net *net)
349+
static unsigned int ipmr_rules_seq_read(const struct net *net)
350350
{
351351
return 0;
352352
}
@@ -3035,11 +3035,9 @@ static const struct net_protocol pim_protocol = {
30353035
};
30363036
#endif
30373037

3038-
static unsigned int ipmr_seq_read(struct net *net)
3038+
static unsigned int ipmr_seq_read(const struct net *net)
30393039
{
3040-
ASSERT_RTNL();
3041-
3042-
return net->ipv4.ipmr_seq + ipmr_rules_seq_read(net);
3040+
return READ_ONCE(net->ipv4.ipmr_seq) + ipmr_rules_seq_read(net);
30433041
}
30443042

30453043
static int ipmr_dump(struct net *net, struct notifier_block *nb,

0 commit comments

Comments
 (0)