summaryrefslogtreecommitdiffstats
path: root/net/bridge/br_netlink.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-10-13 13:58:04 +0200
committerDavid S. Miller <davem@davemloft.net>2015-10-13 13:58:04 +0200
commitbbb300eb976b613a8e4e666d3af39f5ab1031d22 (patch)
treeebe13617bfc4b22390d6a73f73f9a1db9b20deb6 /net/bridge/br_netlink.c
parentMerge branch 'vrf-ipv6' (diff)
parentbridge: vlan: move back vlan_flush (diff)
downloadlinux-bbb300eb976b613a8e4e666d3af39f5ab1031d22.tar.xz
linux-bbb300eb976b613a8e4e666d3af39f5ab1031d22.zip
Merge branch 'bridge-vlan'
Nikolay Aleksandrov says: ==================== bridge: vlan: cleanups & fixes (part 3) Patch 01 converts the vlgrp member to use rcu as it was already used in a similar way so better to make it official and use all the available RCU instrumentation. Patch 02 fixes a bug where the vlan_list can be traversed without rtnl or rcu held which could lead to using freed entries. Patch 03 removes some redundant code that isn't needed anymore. Patch 04 fixes a bug reported by Ido Schimmel about the vlan_flush order and switchdevs, it moves it back. v2: patch 03 and 04 are new, couldn't escape the second synchronize_rcu() since the rhtable destruction can sleep ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_netlink.c')
-rw-r--r--net/bridge/br_netlink.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index d792d1a848ad..94b4de8c4646 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -102,10 +102,10 @@ static size_t br_get_link_af_size_filtered(const struct net_device *dev,
rcu_read_lock();
if (br_port_exists(dev)) {
p = br_port_get_rcu(dev);
- vg = nbp_vlan_group(p);
+ vg = nbp_vlan_group_rcu(p);
} else if (dev->priv_flags & IFF_EBRIDGE) {
br = netdev_priv(dev);
- vg = br_vlan_group(br);
+ vg = br_vlan_group_rcu(br);
}
num_vlan_infos = br_get_num_vlan_infos(vg, filter_mask);
rcu_read_unlock();
@@ -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);