Thread (9 messages) flat view 9 messages, 4 authors, 2024-09-13

Re: [PATCH v2 net 2/5] net: dsa: be compatible with masters which unregister on shutdown

From: Vladimir Oltean <olteanv@gmail.com>
Date: 2024-09-13 20:29:23
Also in: linux-arm-kernel, linux-mediatek, lkml

Hi Alexander,

On Wed, Sep 04, 2024 at 08:31:13AM +0000, Sverdlin, Alexander wrote:
quoted
+static void lan9303_mdio_shutdown(struct mdio_device *mdiodev)
+{
+	struct lan9303_mdio *sw_dev = dev_get_drvdata(&mdiodev->dev);
+
+	if (!sw_dev)
+		return;
+
+	lan9303_shutdown(&sw_dev->chip);
+
+	dev_set_drvdata(&mdiodev->dev, NULL);
 }
This unfortunately didn't work well with LAN9303 and probably will not work
with others:

Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
CPU: 0 PID: 442 Comm: kworker/0:3 Tainted: G           O       6.1.99+gitb7793b7d9b35 #1
Workqueue: events_power_efficient phy_state_machine
pc : lan9303_mdio_phy_read+0x1c/0x34
lr : lan9303_phy_read+0x50/0x100
Call trace:
 lan9303_mdio_phy_read+0x1c/0x34
 lan9303_phy_read+0x50/0x100
 dsa_slave_phy_read+0x40/0x50
 __mdiobus_read+0x34/0x130
 mdiobus_read+0x44/0x70
 genphy_update_link+0x2c/0x104
 genphy_read_status+0x2c/0x120
 phy_check_link_status+0xb8/0xcc
 phy_state_machine+0x198/0x27c
 process_one_work+0x1dc/0x450
 worker_thread+0x154/0x450

as long as the ports are not down (and dsa_switch_shutdown() doesn't ensure it),
we cannot just zero drvdata, because PHY polling will eventually call

static int lan9303_mdio_phy_read(struct lan9303 *chip, int addr, int reg)
{
        struct lan9303_mdio *sw_dev = dev_get_drvdata(chip->dev);

        return mdiobus_read_nested(sw_dev->device->bus, addr, reg);

There are however multiple other unsafe patterns.
I suppose current

dsa_switch_shutdown();
dev_set_drvdata(...->dev, NULL);

pattern is broken in many cases...
Unfortunately the code portion which you've quoted for your reply does not
show the full story. dsa_switch_shutdown(), at the time of this patch,
was implemented like this (stripped of comments):

void dsa_switch_shutdown(struct dsa_switch *ds)
{
	struct net_device *master, *slave_dev;
	LIST_HEAD(unregister_list);
	struct dsa_port *dp;

	mutex_lock(&dsa2_mutex);
	rtnl_lock();

	list_for_each_entry(dp, &ds->dst->ports, list) {
		if (dp->ds != ds)
			continue;

		if (!dsa_port_is_user(dp))
			continue;

		master = dp->cpu_dp->master;
		slave_dev = dp->slave;

		netdev_upper_dev_unlink(master, slave_dev);
		unregister_netdevice_queue(slave_dev, &unregister_list);
	}
	unregister_netdevice_many(&unregister_list);

	rtnl_unlock();
	mutex_unlock(&dsa2_mutex);
}

I believe you would be wrong to blame this patch for exiting with the
slave/user ports still running (and thus ds->ops->phy_read() still
callable), because, as you can see, it doesn't do that - it unregisters
them, which also stops the net_device prior. So, both phylink_stop() and
phylink_destroy() would be called.

The patch had other problems though, and that led to the rework in
commit ee534378f005 ("net: dsa: fix panic when DSA master device unbinds
on shutdown"), rework which is in fact to blame for what you're reporting.

Given that we are talking about a fix to a fix, it doesn't really matter
in terms of backporting targets which one it is, but for correctness sake,
it is the later patch that fixed some things while introducing the race
condition.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help