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:
Родитель
907b1e6e83
Коммит
e9c953eff7
|
@ -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,
|
||||||
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,
|
||||||
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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче