Skip to content

Commit cf5ca4d

Browse files
vladimirolteankuba-moo
authored andcommitted
net: dsa: don't leave dangling pointers in dp->pl when failing
There is a desire to simplify the dsa_port registration path with devlink, and this involves reworking a bit how user ports which fail to connect to their PHY (because it's missing) get reinitialized as UNUSED devlink ports. The desire is for the change to look something like this; basically dsa_port_setup() has failed, we just change dp->type and call dsa_port_setup() again. -/* Destroy the current devlink port, and create a new one which has the UNUSED - * flavour. - */ -static int dsa_port_reinit_as_unused(struct dsa_port *dp) +static int dsa_port_setup_as_unused(struct dsa_port *dp) { - dsa_port_devlink_teardown(dp); dp->type = DSA_PORT_TYPE_UNUSED; - return dsa_port_devlink_setup(dp); + return dsa_port_setup(dp); } For an UNUSED port, dsa_port_setup() mostly only calls dsa_port_devlink_setup() anyway, so we could get away with calling just that. But if we call the full blown dsa_port_setup(dp) (which will be needed to properly set dp->setup = true), the callee will have the tendency to go through this code block too, and call dsa_port_disable(dp): switch (dp->type) { case DSA_PORT_TYPE_UNUSED: dsa_port_disable(dp); break; That is not very good, because dsa_port_disable() has this hidden inside of it: if (dp->pl) phylink_stop(dp->pl); Fact is, we are not prepared to handle a call to dsa_port_disable() with a struct dsa_port that came from a previous (and failed) call to dsa_port_setup(). We do not clean up dp->pl, and this will make the second call to dsa_port_setup() call phylink_stop() on a dangling dp->pl pointer. Solve this by creating an API for phylink destruction which is symmetric to the phylink creation, and never leave dp->pl set to anything except NULL or a valid phylink structure. Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent d82acd8 commit cf5ca4d

File tree

3 files changed

+19
-10
lines changed

3 files changed

+19
-10
lines changed

net/dsa/dsa_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
294294
int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
295295
const struct switchdev_obj_ring_role_mrp *mrp);
296296
int dsa_port_phylink_create(struct dsa_port *dp);
297+
void dsa_port_phylink_destroy(struct dsa_port *dp);
297298
int dsa_shared_port_link_register_of(struct dsa_port *dp);
298299
void dsa_shared_port_link_unregister_of(struct dsa_port *dp);
299300
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);

net/dsa/port.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
16611661
{
16621662
struct dsa_switch *ds = dp->ds;
16631663
phy_interface_t mode;
1664+
struct phylink *pl;
16641665
int err;
16651666

16661667
err = of_get_phy_mode(dp->dn, &mode);
@@ -1677,16 +1678,24 @@ int dsa_port_phylink_create(struct dsa_port *dp)
16771678
if (ds->ops->phylink_get_caps)
16781679
ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config);
16791680

1680-
dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
1681-
mode, &dsa_port_phylink_mac_ops);
1682-
if (IS_ERR(dp->pl)) {
1681+
pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
1682+
mode, &dsa_port_phylink_mac_ops);
1683+
if (IS_ERR(pl)) {
16831684
pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl));
1684-
return PTR_ERR(dp->pl);
1685+
return PTR_ERR(pl);
16851686
}
16861687

1688+
dp->pl = pl;
1689+
16871690
return 0;
16881691
}
16891692

1693+
void dsa_port_phylink_destroy(struct dsa_port *dp)
1694+
{
1695+
phylink_destroy(dp->pl);
1696+
dp->pl = NULL;
1697+
}
1698+
16901699
static int dsa_shared_port_setup_phy_of(struct dsa_port *dp, bool enable)
16911700
{
16921701
struct dsa_switch *ds = dp->ds;
@@ -1781,7 +1790,7 @@ static int dsa_shared_port_phylink_register(struct dsa_port *dp)
17811790
return 0;
17821791

17831792
err_phy_connect:
1784-
phylink_destroy(dp->pl);
1793+
dsa_port_phylink_destroy(dp);
17851794
return err;
17861795
}
17871796

@@ -1983,8 +1992,7 @@ void dsa_shared_port_link_unregister_of(struct dsa_port *dp)
19831992
rtnl_lock();
19841993
phylink_disconnect_phy(dp->pl);
19851994
rtnl_unlock();
1986-
phylink_destroy(dp->pl);
1987-
dp->pl = NULL;
1995+
dsa_port_phylink_destroy(dp);
19881996
return;
19891997
}
19901998

net/dsa/slave.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,7 +2304,7 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
23042304
if (ret) {
23052305
netdev_err(slave_dev, "failed to connect to PHY: %pe\n",
23062306
ERR_PTR(ret));
2307-
phylink_destroy(dp->pl);
2307+
dsa_port_phylink_destroy(dp);
23082308
}
23092309

23102310
return ret;
@@ -2476,7 +2476,7 @@ int dsa_slave_create(struct dsa_port *port)
24762476
rtnl_lock();
24772477
phylink_disconnect_phy(p->dp->pl);
24782478
rtnl_unlock();
2479-
phylink_destroy(p->dp->pl);
2479+
dsa_port_phylink_destroy(p->dp);
24802480
out_gcells:
24812481
gro_cells_destroy(&p->gcells);
24822482
out_free:
@@ -2499,7 +2499,7 @@ void dsa_slave_destroy(struct net_device *slave_dev)
24992499
phylink_disconnect_phy(dp->pl);
25002500
rtnl_unlock();
25012501

2502-
phylink_destroy(dp->pl);
2502+
dsa_port_phylink_destroy(dp);
25032503
gro_cells_destroy(&p->gcells);
25042504
free_percpu(slave_dev->tstats);
25052505
free_netdev(slave_dev);

0 commit comments

Comments
 (0)