summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2022-03-18 22:54:43 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-04-08 15:23:43 +0300
commit95df5cd5a446df6738d2d45872e08594819080e4 (patch)
treedd2b3993106bc44f245c3d38c16b66a68adb5465 /net
parent894347d4d29bcdaa4ed3e817cf4dd88fafb48e9c (diff)
downloadlinux-95df5cd5a446df6738d2d45872e08594819080e4.tar.xz
net: dsa: fix panic on shutdown if multi-chip tree failed to probe
[ Upstream commit 8fd36358ce82382519b50b05f437493e1e00c4a9 ] DSA probing is atypical because a tree of devices must probe all at once, so out of N switches which call dsa_tree_setup_routing_table() during probe, for (N - 1) of them, "complete" will return false and they will exit probing early. The Nth switch will set up the whole tree on their behalf. The implication is that for (N - 1) switches, the driver binds to the device successfully, without doing anything. When the driver is bound, the ->shutdown() method may run. But if the Nth switch has failed to initialize the tree, there is nothing to do for the (N - 1) driver instances, since the slave devices have not been created, etc. Moreover, dsa_switch_shutdown() expects that the calling @ds has been in fact initialized, so it jumps at dereferencing the various data structures, which is incorrect. Avoid the ensuing NULL pointer dereferences by simply checking whether the Nth switch has previously set "ds->setup = true" for the switch which is currently shutting down. The entire setup is serialized under dsa2_mutex which we already hold. Fixes: 0650bf52b31f ("net: dsa: be compatible with masters which unregister on shutdown") Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Link: https://lore.kernel.org/r/20220318195443.275026-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/dsa/dsa2.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index e7fa8ce41a4c..64a56db3de58 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1631,6 +1631,10 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
struct dsa_port *dp;
mutex_lock(&dsa2_mutex);
+
+ if (!ds->setup)
+ goto out;
+
rtnl_lock();
list_for_each_entry(dp, &ds->dst->ports, list) {
@@ -1665,6 +1669,7 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
unregister_netdevice_many(&unregister_list);
rtnl_unlock();
+out:
mutex_unlock(&dsa2_mutex);
}
EXPORT_SYMBOL_GPL(dsa_switch_shutdown);