summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Oltean <olteanv@gmail.com>2019-08-31 08:46:19 -0400
committerDavid S. Miller <davem@davemloft.net>2019-09-02 14:59:29 -0400
commit4ba0ebbc6cdecb9fad7c551a3d97b172ebc7b2fa (patch)
tree9c916da84bff3525eeadb6cdcb859f537da5a8d4
parenta21cf11bc57fca136f98e81ebc6a6eaf52952b8f (diff)
net: dsa: Fix off-by-one number of calls to devlink_port_unregister
When a function such as dsa_slave_create fails, currently the following stack trace can be seen: [ 2.038342] sja1105 spi0.1: Probed switch chip: SJA1105T [ 2.054556] sja1105 spi0.1: Reset switch and programmed static config [ 2.063837] sja1105 spi0.1: Enabled switch tagging [ 2.068706] fsl-gianfar soc:ethernet@2d90000 eth2: error -19 setting up slave phy [ 2.076371] ------------[ cut here ]------------ [ 2.080973] WARNING: CPU: 1 PID: 21 at net/core/devlink.c:6184 devlink_free+0x1b4/0x1c0 [ 2.088954] Modules linked in: [ 2.092005] CPU: 1 PID: 21 Comm: kworker/1:1 Not tainted 5.3.0-rc6-01360-g41b52e38d2b6-dirty #1746 [ 2.100912] Hardware name: Freescale LS1021A [ 2.105162] Workqueue: events deferred_probe_work_func [ 2.110287] [<c03133a4>] (unwind_backtrace) from [<c030d8cc>] (show_stack+0x10/0x14) [ 2.117992] [<c030d8cc>] (show_stack) from [<c10b08d8>] (dump_stack+0xb4/0xc8) [ 2.125180] [<c10b08d8>] (dump_stack) from [<c0349d04>] (__warn+0xe0/0xf8) [ 2.132018] [<c0349d04>] (__warn) from [<c0349e34>] (warn_slowpath_null+0x40/0x48) [ 2.139549] [<c0349e34>] (warn_slowpath_null) from [<c0f19d74>] (devlink_free+0x1b4/0x1c0) [ 2.147772] [<c0f19d74>] (devlink_free) from [<c1064fc0>] (dsa_switch_teardown+0x60/0x6c) [ 2.155907] [<c1064fc0>] (dsa_switch_teardown) from [<c1065950>] (dsa_register_switch+0x8e4/0xaa8) [ 2.164821] [<c1065950>] (dsa_register_switch) from [<c0ba7fe4>] (sja1105_probe+0x21c/0x2ec) [ 2.173216] [<c0ba7fe4>] (sja1105_probe) from [<c0b35948>] (spi_drv_probe+0x80/0xa4) [ 2.180920] [<c0b35948>] (spi_drv_probe) from [<c0a4c1cc>] (really_probe+0x108/0x400) [ 2.188711] [<c0a4c1cc>] (really_probe) from [<c0a4c694>] (driver_probe_device+0x78/0x1bc) [ 2.196933] [<c0a4c694>] (driver_probe_device) from [<c0a4a3dc>] (bus_for_each_drv+0x58/0xb8) [ 2.205414] [<c0a4a3dc>] (bus_for_each_drv) from [<c0a4c024>] (__device_attach+0xd0/0x168) [ 2.213637] [<c0a4c024>] (__device_attach) from [<c0a4b1d0>] (bus_probe_device+0x84/0x8c) [ 2.221772] [<c0a4b1d0>] (bus_probe_device) from [<c0a4b72c>] (deferred_probe_work_func+0x84/0xc4) [ 2.230686] [<c0a4b72c>] (deferred_probe_work_func) from [<c03650a4>] (process_one_work+0x218/0x510) [ 2.239772] [<c03650a4>] (process_one_work) from [<c03660d8>] (worker_thread+0x2a8/0x5c0) [ 2.247908] [<c03660d8>] (worker_thread) from [<c036b348>] (kthread+0x148/0x150) [ 2.255265] [<c036b348>] (kthread) from [<c03010e8>] (ret_from_fork+0x14/0x2c) [ 2.262444] Exception stack(0xea965fb0 to 0xea965ff8) [ 2.267466] 5fa0: 00000000 00000000 00000000 00000000 [ 2.275598] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 2.283729] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 [ 2.290333] ---[ end trace ca5d506728a0581a ]--- devlink_free is complaining right here: WARN_ON(!list_empty(&devlink->port_list)); This happens because devlink_port_unregister is no longer done right away in dsa_port_setup when a DSA_PORT_TYPE_USER has failed. Vivien said about this change that: Also no need to call devlink_port_unregister from within dsa_port_setup as this step is inconditionally handled by dsa_port_teardown on error. which is not really true. The devlink_port_unregister function _is_ being called unconditionally from within dsa_port_setup, but not for this port that just failed, just for the previous ones which were set up. ports_teardown: for (i = 0; i < port; i++) dsa_port_teardown(&ds->ports[i]); Initially I was tempted to fix this by extending the "for" loop to also cover the port that failed during setup. But this could have potentially unforeseen consequences unrelated to devlink_port or even other types of ports than user ports, which I can't really test for. For example, if for some reason devlink_port_register itself would fail, then unconditionally unregistering it in dsa_port_teardown would not be a smart idea. The list might go on. So just make dsa_port_setup undo the setup it had done upon failure, and let the for loop undo the work of setting up the previous ports, which are guaranteed to be brought up to a consistent state. Fixes: 955222ca5281 ("net: dsa: use a single switch statement for port setup") Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Reviewed-by: Vivien Didelot <vivien.didelot@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/dsa/dsa2.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index f8445fa73448..b501c90aabe4 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -259,8 +259,11 @@ static int dsa_port_setup(struct dsa_port *dp)
259 const unsigned char *id = (const unsigned char *)&dst->index; 259 const unsigned char *id = (const unsigned char *)&dst->index;
260 const unsigned char len = sizeof(dst->index); 260 const unsigned char len = sizeof(dst->index);
261 struct devlink_port *dlp = &dp->devlink_port; 261 struct devlink_port *dlp = &dp->devlink_port;
262 bool dsa_port_link_registered = false;
263 bool devlink_port_registered = false;
262 struct devlink *dl = ds->devlink; 264 struct devlink *dl = ds->devlink;
263 int err; 265 bool dsa_port_enabled = false;
266 int err = 0;
264 267
265 switch (dp->type) { 268 switch (dp->type) {
266 case DSA_PORT_TYPE_UNUSED: 269 case DSA_PORT_TYPE_UNUSED:
@@ -272,15 +275,19 @@ static int dsa_port_setup(struct dsa_port *dp)
272 dp->index, false, 0, id, len); 275 dp->index, false, 0, id, len);
273 err = devlink_port_register(dl, dlp, dp->index); 276 err = devlink_port_register(dl, dlp, dp->index);
274 if (err) 277 if (err)
275 return err; 278 break;
279 devlink_port_registered = true;
276 280
277 err = dsa_port_link_register_of(dp); 281 err = dsa_port_link_register_of(dp);
278 if (err) 282 if (err)
279 return err; 283 break;
284 dsa_port_link_registered = true;
280 285
281 err = dsa_port_enable(dp, NULL); 286 err = dsa_port_enable(dp, NULL);
282 if (err) 287 if (err)
283 return err; 288 break;
289 dsa_port_enabled = true;
290
284 break; 291 break;
285 case DSA_PORT_TYPE_DSA: 292 case DSA_PORT_TYPE_DSA:
286 memset(dlp, 0, sizeof(*dlp)); 293 memset(dlp, 0, sizeof(*dlp));
@@ -288,15 +295,19 @@ static int dsa_port_setup(struct dsa_port *dp)
288 dp->index, false, 0, id, len); 295 dp->index, false, 0, id, len);
289 err = devlink_port_register(dl, dlp, dp->index); 296 err = devlink_port_register(dl, dlp, dp->index);
290 if (err) 297 if (err)
291 return err; 298 break;
299 devlink_port_registered = true;
292 300
293 err = dsa_port_link_register_of(dp); 301 err = dsa_port_link_register_of(dp);
294 if (err) 302 if (err)
295 return err; 303 break;
304 dsa_port_link_registered = true;
296 305
297 err = dsa_port_enable(dp, NULL); 306 err = dsa_port_enable(dp, NULL);
298 if (err) 307 if (err)
299 return err; 308 break;
309 dsa_port_enabled = true;
310
300 break; 311 break;
301 case DSA_PORT_TYPE_USER: 312 case DSA_PORT_TYPE_USER:
302 memset(dlp, 0, sizeof(*dlp)); 313 memset(dlp, 0, sizeof(*dlp));
@@ -304,18 +315,26 @@ static int dsa_port_setup(struct dsa_port *dp)
304 dp->index, false, 0, id, len); 315 dp->index, false, 0, id, len);
305 err = devlink_port_register(dl, dlp, dp->index); 316 err = devlink_port_register(dl, dlp, dp->index);
306 if (err) 317 if (err)
307 return err; 318 break;
319 devlink_port_registered = true;
308 320
309 dp->mac = of_get_mac_address(dp->dn); 321 dp->mac = of_get_mac_address(dp->dn);
310 err = dsa_slave_create(dp); 322 err = dsa_slave_create(dp);
311 if (err) 323 if (err)
312 return err; 324 break;
313 325
314 devlink_port_type_eth_set(dlp, dp->slave); 326 devlink_port_type_eth_set(dlp, dp->slave);
315 break; 327 break;
316 } 328 }
317 329
318 return 0; 330 if (err && dsa_port_enabled)
331 dsa_port_disable(dp);
332 if (err && dsa_port_link_registered)
333 dsa_port_link_unregister_of(dp);
334 if (err && devlink_port_registered)
335 devlink_port_unregister(dlp);
336
337 return err;
319} 338}
320 339
321static void dsa_port_teardown(struct dsa_port *dp) 340static void dsa_port_teardown(struct dsa_port *dp)