Commit e9c953ef authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by David S. Miller

bridge: vlan: use rcu for vlan_list traversal in br_fill_ifinfo

br_fill_ifinfo is called by br_ifinfo_notify which can be called from
many contexts with different locks held, sometimes it relies upon
bridge's spinlock only which is a problem for the vlan code, so use
explicitly rcu for that to avoid problems.
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Reviewed-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 907b1e6e
...@@ -253,7 +253,7 @@ static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb, ...@@ -253,7 +253,7 @@ static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
* if vlaninfo represents a range * if vlaninfo represents a range
*/ */
pvid = br_get_pvid(vg); pvid = br_get_pvid(vg);
list_for_each_entry(v, &vg->vlan_list, vlist) { list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
flags = 0; flags = 0;
if (!br_vlan_should_use(v)) if (!br_vlan_should_use(v))
continue; continue;
...@@ -303,7 +303,7 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb, ...@@ -303,7 +303,7 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb,
u16 pvid; u16 pvid;
pvid = br_get_pvid(vg); pvid = br_get_pvid(vg);
list_for_each_entry(v, &vg->vlan_list, vlist) { list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
if (!br_vlan_should_use(v)) if (!br_vlan_should_use(v))
continue; continue;
...@@ -386,22 +386,27 @@ static int br_fill_ifinfo(struct sk_buff *skb, ...@@ -386,22 +386,27 @@ static int br_fill_ifinfo(struct sk_buff *skb,
struct nlattr *af; struct nlattr *af;
int err; int err;
/* RCU needed because of the VLAN locking rules (rcu || rtnl) */
rcu_read_lock();
if (port) if (port)
vg = nbp_vlan_group(port); vg = nbp_vlan_group_rcu(port);
else else
vg = br_vlan_group(br); vg = br_vlan_group_rcu(br);
if (!vg || !vg->num_vlans) if (!vg || !vg->num_vlans) {
rcu_read_unlock();
goto done; goto done;
}
af = nla_nest_start(skb, IFLA_AF_SPEC); af = nla_nest_start(skb, IFLA_AF_SPEC);
if (!af) if (!af) {
rcu_read_unlock();
goto nla_put_failure; goto nla_put_failure;
}
if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
err = br_fill_ifvlaninfo_compressed(skb, vg); err = br_fill_ifvlaninfo_compressed(skb, vg);
else else
err = br_fill_ifvlaninfo(skb, vg); err = br_fill_ifvlaninfo(skb, vg);
rcu_read_unlock();
if (err) if (err)
goto nla_put_failure; goto nla_put_failure;
nla_nest_end(skb, af); nla_nest_end(skb, af);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment