diff options
author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2022-03-08 11:15:11 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2022-03-09 11:12:09 +0000 |
commit | fe95784fb14e4d56072b7be7325ef859efa38135 (patch) | |
tree | abc27edb1719d8a69ab57aa5c2000197dd620998 /net/dsa | |
parent | 0832cd9f1f023226527e95002d537123061ddac4 (diff) | |
download | linux-fe95784fb14e4d56072b7be7325ef859efa38135.tar.bz2 |
net: dsa: move port lists initialization to dsa_port_touch
&cpu_db->fdbs and &cpu_db->mdbs may be uninitialized lists during some
call paths of felix_set_tag_protocol().
There was an attempt to avoid calling dsa_port_walk_fdbs() during setup
by using a "bool change" in the felix driver, but this doesn't work when
the tagging protocol is defined in the device tree, and a change is
triggered by DSA at pseudo-runtime:
dsa_tree_setup_switches
-> dsa_switch_setup
-> dsa_switch_setup_tag_protocol
-> ds->ops->change_tag_protocol
dsa_tree_setup_ports
-> dsa_port_setup
-> &dp->fdbs and &db->mdbs only get initialized here
So it seems like the only way to fix this is to move the initialization
of these lists earlier.
dsa_port_touch() is called from dsa_switch_touch_ports() which is called
from dsa_switch_parse_of(), and this runs completely before
dsa_tree_setup(). Similarly, dsa_switch_release_ports() runs after
dsa_tree_teardown().
Fixes: f9cef64fa23f ("net: dsa: felix: migrate host FDB and MDB entries when changing tag proto")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r-- | net/dsa/dsa2.c | 18 |
1 files changed, 8 insertions, 10 deletions
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 04065d3fb09f..39e696185720 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -457,12 +457,6 @@ static int dsa_port_setup(struct dsa_port *dp) if (dp->setup) return 0; - mutex_init(&dp->addr_lists_lock); - mutex_init(&dp->vlans_lock); - INIT_LIST_HEAD(&dp->fdbs); - INIT_LIST_HEAD(&dp->mdbs); - INIT_LIST_HEAD(&dp->vlans); - if (ds->ops->port_setup) { err = ds->ops->port_setup(ds, dp->index); if (err) @@ -599,10 +593,6 @@ static void dsa_port_teardown(struct dsa_port *dp) break; } - WARN_ON(!list_empty(&dp->fdbs)); - WARN_ON(!list_empty(&dp->mdbs)); - WARN_ON(!list_empty(&dp->vlans)); - dp->setup = false; } @@ -1361,6 +1351,11 @@ static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) dp->ds = ds; dp->index = index; + mutex_init(&dp->addr_lists_lock); + mutex_init(&dp->vlans_lock); + INIT_LIST_HEAD(&dp->fdbs); + INIT_LIST_HEAD(&dp->mdbs); + INIT_LIST_HEAD(&dp->vlans); INIT_LIST_HEAD(&dp->list); list_add_tail(&dp->list, &dst->ports); @@ -1699,6 +1694,9 @@ static void dsa_switch_release_ports(struct dsa_switch *ds) struct dsa_port *dp, *next; dsa_switch_for_each_port_safe(dp, next, ds) { + WARN_ON(!list_empty(&dp->fdbs)); + WARN_ON(!list_empty(&dp->mdbs)); + WARN_ON(!list_empty(&dp->vlans)); list_del(&dp->list); kfree(dp); } |