mirror of https://gitee.com/openkylin/linux.git
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: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
907b1e6e83
commit
e9c953eff7
|
@ -253,7 +253,7 @@ static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
|
|||
* if vlaninfo represents a range
|
||||
*/
|
||||
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;
|
||||
if (!br_vlan_should_use(v))
|
||||
continue;
|
||||
|
@ -303,7 +303,7 @@ static int br_fill_ifvlaninfo(struct sk_buff *skb,
|
|||
u16 pvid;
|
||||
|
||||
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))
|
||||
continue;
|
||||
|
||||
|
@ -386,22 +386,27 @@ static int br_fill_ifinfo(struct sk_buff *skb,
|
|||
struct nlattr *af;
|
||||
int err;
|
||||
|
||||
/* RCU needed because of the VLAN locking rules (rcu || rtnl) */
|
||||
rcu_read_lock();
|
||||
if (port)
|
||||
vg = nbp_vlan_group(port);
|
||||
vg = nbp_vlan_group_rcu(port);
|
||||
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;
|
||||
|
||||
}
|
||||
af = nla_nest_start(skb, IFLA_AF_SPEC);
|
||||
if (!af)
|
||||
if (!af) {
|
||||
rcu_read_unlock();
|
||||
goto nla_put_failure;
|
||||
|
||||
}
|
||||
if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
|
||||
err = br_fill_ifvlaninfo_compressed(skb, vg);
|
||||
else
|
||||
err = br_fill_ifvlaninfo(skb, vg);
|
||||
rcu_read_unlock();
|
||||
if (err)
|
||||
goto nla_put_failure;
|
||||
nla_nest_end(skb, af);
|
||||
|
|
Loading…
Reference in New Issue