Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -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);