Skip to content

Commit 874d7ce

Browse files
Stanislav FomichevNipaLocal
authored andcommitted
team: replace team lock with rtnl lock
syszbot reports various ordering issues for lower instance locks and team lock. Switch to using rtnl lock for protecting team device, similar to bonding. Based on the patch by Tetsuo Handa. Cc: Jiri Pirko <[email protected]> Cc: Tetsuo Handa <[email protected]> Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=705c61d60b091ef42c04 Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=71fd22ae4b81631e22fd Fixes: 6b1d3c5 ("team: grab team lock during team_change_rx_flags") Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Stanislav Fomichev <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent 0b26df8 commit 874d7ce

File tree

4 files changed

+50
-65
lines changed

4 files changed

+50
-65
lines changed

drivers/net/team/team_core.c

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ static bool team_port_find(const struct team *team,
933933
* Enable/disable port by adding to enabled port hashlist and setting
934934
* port->index (Might be racy so reader could see incorrect ifindex when
935935
* processing a flying packet, but that is not a problem). Write guarded
936-
* by team->lock.
936+
* by RTNL.
937937
*/
938938
static void team_port_enable(struct team *team,
939939
struct team_port *port)
@@ -1660,8 +1660,6 @@ static int team_init(struct net_device *dev)
16601660
goto err_options_register;
16611661
netif_carrier_off(dev);
16621662

1663-
lockdep_register_key(&team->team_lock_key);
1664-
__mutex_init(&team->lock, "team->team_lock_key", &team->team_lock_key);
16651663
netdev_lockdep_set_classes(dev);
16661664

16671665
return 0;
@@ -1682,7 +1680,8 @@ static void team_uninit(struct net_device *dev)
16821680
struct team_port *port;
16831681
struct team_port *tmp;
16841682

1685-
mutex_lock(&team->lock);
1683+
ASSERT_RTNL();
1684+
16861685
list_for_each_entry_safe(port, tmp, &team->port_list, list)
16871686
team_port_del(team, port->dev);
16881687

@@ -1691,9 +1690,7 @@ static void team_uninit(struct net_device *dev)
16911690
team_mcast_rejoin_fini(team);
16921691
team_notify_peers_fini(team);
16931692
team_queue_override_fini(team);
1694-
mutex_unlock(&team->lock);
16951693
netdev_change_features(dev);
1696-
lockdep_unregister_key(&team->team_lock_key);
16971694
}
16981695

16991696
static void team_destructor(struct net_device *dev)
@@ -1778,7 +1775,8 @@ static void team_change_rx_flags(struct net_device *dev, int change)
17781775
struct team_port *port;
17791776
int inc;
17801777

1781-
mutex_lock(&team->lock);
1778+
ASSERT_RTNL();
1779+
17821780
list_for_each_entry(port, &team->port_list, list) {
17831781
if (change & IFF_PROMISC) {
17841782
inc = dev->flags & IFF_PROMISC ? 1 : -1;
@@ -1789,7 +1787,6 @@ static void team_change_rx_flags(struct net_device *dev, int change)
17891787
dev_set_allmulti(port->dev, inc);
17901788
}
17911789
}
1792-
mutex_unlock(&team->lock);
17931790
}
17941791

17951792
static void team_set_rx_mode(struct net_device *dev)
@@ -1811,14 +1808,14 @@ static int team_set_mac_address(struct net_device *dev, void *p)
18111808
struct team *team = netdev_priv(dev);
18121809
struct team_port *port;
18131810

1811+
ASSERT_RTNL();
1812+
18141813
if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
18151814
return -EADDRNOTAVAIL;
18161815
dev_addr_set(dev, addr->sa_data);
1817-
mutex_lock(&team->lock);
18181816
list_for_each_entry(port, &team->port_list, list)
18191817
if (team->ops.port_change_dev_addr)
18201818
team->ops.port_change_dev_addr(team, port);
1821-
mutex_unlock(&team->lock);
18221819
return 0;
18231820
}
18241821

@@ -1828,11 +1825,8 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
18281825
struct team_port *port;
18291826
int err;
18301827

1831-
/*
1832-
* Alhough this is reader, it's guarded by team lock. It's not possible
1833-
* to traverse list in reverse under rcu_read_lock
1834-
*/
1835-
mutex_lock(&team->lock);
1828+
ASSERT_RTNL();
1829+
18361830
team->port_mtu_change_allowed = true;
18371831
list_for_each_entry(port, &team->port_list, list) {
18381832
err = dev_set_mtu(port->dev, new_mtu);
@@ -1843,7 +1837,6 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
18431837
}
18441838
}
18451839
team->port_mtu_change_allowed = false;
1846-
mutex_unlock(&team->lock);
18471840

18481841
WRITE_ONCE(dev->mtu, new_mtu);
18491842

@@ -1853,7 +1846,6 @@ static int team_change_mtu(struct net_device *dev, int new_mtu)
18531846
list_for_each_entry_continue_reverse(port, &team->port_list, list)
18541847
dev_set_mtu(port->dev, dev->mtu);
18551848
team->port_mtu_change_allowed = false;
1856-
mutex_unlock(&team->lock);
18571849

18581850
return err;
18591851
}
@@ -1903,24 +1895,19 @@ static int team_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
19031895
struct team_port *port;
19041896
int err;
19051897

1906-
/*
1907-
* Alhough this is reader, it's guarded by team lock. It's not possible
1908-
* to traverse list in reverse under rcu_read_lock
1909-
*/
1910-
mutex_lock(&team->lock);
1898+
ASSERT_RTNL();
1899+
19111900
list_for_each_entry(port, &team->port_list, list) {
19121901
err = vlan_vid_add(port->dev, proto, vid);
19131902
if (err)
19141903
goto unwind;
19151904
}
1916-
mutex_unlock(&team->lock);
19171905

19181906
return 0;
19191907

19201908
unwind:
19211909
list_for_each_entry_continue_reverse(port, &team->port_list, list)
19221910
vlan_vid_del(port->dev, proto, vid);
1923-
mutex_unlock(&team->lock);
19241911

19251912
return err;
19261913
}
@@ -1930,10 +1917,10 @@ static int team_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
19301917
struct team *team = netdev_priv(dev);
19311918
struct team_port *port;
19321919

1933-
mutex_lock(&team->lock);
1920+
ASSERT_RTNL();
1921+
19341922
list_for_each_entry(port, &team->port_list, list)
19351923
vlan_vid_del(port->dev, proto, vid);
1936-
mutex_unlock(&team->lock);
19371924

19381925
return 0;
19391926
}
@@ -1955,9 +1942,9 @@ static void team_netpoll_cleanup(struct net_device *dev)
19551942
{
19561943
struct team *team = netdev_priv(dev);
19571944

1958-
mutex_lock(&team->lock);
1945+
ASSERT_RTNL();
1946+
19591947
__team_netpoll_cleanup(team);
1960-
mutex_unlock(&team->lock);
19611948
}
19621949

19631950
static int team_netpoll_setup(struct net_device *dev)
@@ -1966,15 +1953,15 @@ static int team_netpoll_setup(struct net_device *dev)
19661953
struct team_port *port;
19671954
int err = 0;
19681955

1969-
mutex_lock(&team->lock);
1956+
ASSERT_RTNL();
1957+
19701958
list_for_each_entry(port, &team->port_list, list) {
19711959
err = __team_port_enable_netpoll(port);
19721960
if (err) {
19731961
__team_netpoll_cleanup(team);
19741962
break;
19751963
}
19761964
}
1977-
mutex_unlock(&team->lock);
19781965
return err;
19791966
}
19801967
#endif
@@ -1985,9 +1972,9 @@ static int team_add_slave(struct net_device *dev, struct net_device *port_dev,
19851972
struct team *team = netdev_priv(dev);
19861973
int err;
19871974

1988-
mutex_lock(&team->lock);
1975+
ASSERT_RTNL();
1976+
19891977
err = team_port_add(team, port_dev, extack);
1990-
mutex_unlock(&team->lock);
19911978

19921979
if (!err)
19931980
netdev_change_features(dev);
@@ -2000,18 +1987,13 @@ static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
20001987
struct team *team = netdev_priv(dev);
20011988
int err;
20021989

2003-
mutex_lock(&team->lock);
1990+
ASSERT_RTNL();
1991+
20041992
err = team_port_del(team, port_dev);
2005-
mutex_unlock(&team->lock);
20061993

20071994
if (err)
20081995
return err;
20091996

2010-
if (netif_is_team_master(port_dev)) {
2011-
lockdep_unregister_key(&team->team_lock_key);
2012-
lockdep_register_key(&team->team_lock_key);
2013-
lockdep_set_class(&team->lock, &team->team_lock_key);
2014-
}
20151997
netdev_change_features(dev);
20161998

20171999
return err;
@@ -2304,9 +2286,10 @@ int team_nl_noop_doit(struct sk_buff *skb, struct genl_info *info)
23042286
static struct team *team_nl_team_get(struct genl_info *info)
23052287
{
23062288
struct net *net = genl_info_net(info);
2307-
int ifindex;
23082289
struct net_device *dev;
2309-
struct team *team;
2290+
int ifindex;
2291+
2292+
ASSERT_RTNL();
23102293

23112294
if (!info->attrs[TEAM_ATTR_TEAM_IFINDEX])
23122295
return NULL;
@@ -2318,14 +2301,11 @@ static struct team *team_nl_team_get(struct genl_info *info)
23182301
return NULL;
23192302
}
23202303

2321-
team = netdev_priv(dev);
2322-
mutex_lock(&team->lock);
2323-
return team;
2304+
return netdev_priv(dev);
23242305
}
23252306

23262307
static void team_nl_team_put(struct team *team)
23272308
{
2328-
mutex_unlock(&team->lock);
23292309
dev_put(team->dev);
23302310
}
23312311

@@ -2515,9 +2495,13 @@ int team_nl_options_get_doit(struct sk_buff *skb, struct genl_info *info)
25152495
int err;
25162496
LIST_HEAD(sel_opt_inst_list);
25172497

2498+
rtnl_lock();
2499+
25182500
team = team_nl_team_get(info);
2519-
if (!team)
2520-
return -EINVAL;
2501+
if (!team) {
2502+
err = -EINVAL;
2503+
goto rtnl_unlock;
2504+
}
25212505

25222506
list_for_each_entry(opt_inst, &team->option_inst_list, list)
25232507
list_add_tail(&opt_inst->tmp_list, &sel_opt_inst_list);
@@ -2527,6 +2511,9 @@ int team_nl_options_get_doit(struct sk_buff *skb, struct genl_info *info)
25272511

25282512
team_nl_team_put(team);
25292513

2514+
rtnl_unlock:
2515+
rtnl_unlock();
2516+
25302517
return err;
25312518
}
25322519

@@ -2805,15 +2792,22 @@ int team_nl_port_list_get_doit(struct sk_buff *skb,
28052792
struct team *team;
28062793
int err;
28072794

2795+
rtnl_lock();
2796+
28082797
team = team_nl_team_get(info);
2809-
if (!team)
2810-
return -EINVAL;
2798+
if (!team) {
2799+
err = -EINVAL;
2800+
goto rtnl_unlock;
2801+
}
28112802

28122803
err = team_nl_send_port_list_get(team, info->snd_portid, info->snd_seq,
28132804
NLM_F_ACK, team_nl_send_unicast, NULL);
28142805

28152806
team_nl_team_put(team);
28162807

2808+
rtnl_unlock:
2809+
rtnl_unlock();
2810+
28172811
return err;
28182812
}
28192813

@@ -2961,11 +2955,9 @@ static void __team_port_change_port_removed(struct team_port *port)
29612955

29622956
static void team_port_change_check(struct team_port *port, bool linkup)
29632957
{
2964-
struct team *team = port->team;
2958+
ASSERT_RTNL();
29652959

2966-
mutex_lock(&team->lock);
29672960
__team_port_change_check(port, linkup);
2968-
mutex_unlock(&team->lock);
29692961
}
29702962

29712963

drivers/net/team/team_mode_activebackup.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ static void ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx)
6767
{
6868
struct team_port *active_port;
6969

70-
active_port = rcu_dereference_protected(ab_priv(team)->active_port,
71-
lockdep_is_held(&team->lock));
70+
active_port = rtnl_dereference(ab_priv(team)->active_port);
7271
if (active_port)
7372
ctx->data.u32_val = active_port->dev->ifindex;
7473
else

drivers/net/team/team_mode_loadbalance.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,7 @@ static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx)
301301
if (lb_priv->ex->orig_fprog) {
302302
/* Clear old filter data */
303303
__fprog_destroy(lb_priv->ex->orig_fprog);
304-
orig_fp = rcu_dereference_protected(lb_priv->fp,
305-
lockdep_is_held(&team->lock));
304+
orig_fp = rtnl_dereference(lb_priv->fp);
306305
}
307306

308307
rcu_assign_pointer(lb_priv->fp, fp);
@@ -324,8 +323,7 @@ static void lb_bpf_func_free(struct team *team)
324323
return;
325324

326325
__fprog_destroy(lb_priv->ex->orig_fprog);
327-
fp = rcu_dereference_protected(lb_priv->fp,
328-
lockdep_is_held(&team->lock));
326+
fp = rtnl_dereference(lb_priv->fp);
329327
bpf_prog_destroy(fp);
330328
}
331329

@@ -335,8 +333,7 @@ static void lb_tx_method_get(struct team *team, struct team_gsetter_ctx *ctx)
335333
lb_select_tx_port_func_t *func;
336334
char *name;
337335

338-
func = rcu_dereference_protected(lb_priv->select_tx_port_func,
339-
lockdep_is_held(&team->lock));
336+
func = rtnl_dereference(lb_priv->select_tx_port_func);
340337
name = lb_select_tx_port_get_name(func);
341338
BUG_ON(!name);
342339
ctx->data.str_val = name;
@@ -478,7 +475,7 @@ static void lb_stats_refresh(struct work_struct *work)
478475
team = lb_priv_ex->team;
479476
lb_priv = get_lb_priv(team);
480477

481-
if (!mutex_trylock(&team->lock)) {
478+
if (!rtnl_trylock()) {
482479
schedule_delayed_work(&lb_priv_ex->stats.refresh_dw, 0);
483480
return;
484481
}
@@ -515,7 +512,7 @@ static void lb_stats_refresh(struct work_struct *work)
515512
schedule_delayed_work(&lb_priv_ex->stats.refresh_dw,
516513
(lb_priv_ex->stats.refresh_interval * HZ) / 10);
517514

518-
mutex_unlock(&team->lock);
515+
rtnl_unlock();
519516
}
520517

521518
static void lb_stats_refresh_interval_get(struct team *team,

include/linux/if_team.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,6 @@ struct team {
191191

192192
const struct header_ops *header_ops_cache;
193193

194-
struct mutex lock; /* used for overall locking, e.g. port lists write */
195-
196194
/*
197195
* List of enabled ports and their count
198196
*/
@@ -223,7 +221,6 @@ struct team {
223221
atomic_t count_pending;
224222
struct delayed_work dw;
225223
} mcast_rejoin;
226-
struct lock_class_key team_lock_key;
227224
long mode_priv[TEAM_MODE_PRIV_LONGS];
228225
};
229226

0 commit comments

Comments
 (0)