summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIoana Ciornei <ioana.ciornei@nxp.com>2019-05-30 02:09:07 -0400
committerDavid S. Miller <davem@davemloft.net>2019-05-30 17:58:31 -0400
commite70c7aad7a95f4f9fd3f00caef1a1ceb57a4b5a4 (patch)
treee0ee84f322f4a3ba72896f90d9cd0dd1b765ea1f
parent1b0b807dd7469e36b761f5bb4ee40b61331aeee8 (diff)
net: dsa: Add error path handling in dsa_tree_setup()
In case a call to dsa_tree_setup() fails, an attempt to cleanup is made by calling dsa_tree_remove_switch(), which should take care of removing/unregistering any resources previously allocated. This does not happen because it is conditioned by dst->setup being true, which is set only after _all_ setup steps were performed successfully. This is especially interesting when the internal MDIO bus is registered but afterwards, a port setup fails and the mdiobus_unregister() is never called. This leads to a BUG_ON() complaining about the fact that it's trying to free an MDIO bus that's still registered. Add proper error handling in all functions branching from dsa_tree_setup(). Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com> Reported-by: kernel test robot <rong.a.chen@intel.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/dsa/dsa2.c89
1 files changed, 66 insertions, 23 deletions
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 3b5f434cad3f..b70befe8a3c8 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -261,7 +261,7 @@ static int dsa_port_setup(struct dsa_port *dp)
261 enum devlink_port_flavour flavour; 261 enum devlink_port_flavour flavour;
262 struct dsa_switch *ds = dp->ds; 262 struct dsa_switch *ds = dp->ds;
263 struct dsa_switch_tree *dst = ds->dst; 263 struct dsa_switch_tree *dst = ds->dst;
264 int err; 264 int err = 0;
265 265
266 if (dp->type == DSA_PORT_TYPE_UNUSED) 266 if (dp->type == DSA_PORT_TYPE_UNUSED)
267 return 0; 267 return 0;
@@ -299,19 +299,15 @@ static int dsa_port_setup(struct dsa_port *dp)
299 break; 299 break;
300 case DSA_PORT_TYPE_CPU: 300 case DSA_PORT_TYPE_CPU:
301 err = dsa_port_link_register_of(dp); 301 err = dsa_port_link_register_of(dp);
302 if (err) { 302 if (err)
303 dev_err(ds->dev, "failed to setup link for port %d.%d\n", 303 dev_err(ds->dev, "failed to setup link for port %d.%d\n",
304 ds->index, dp->index); 304 ds->index, dp->index);
305 return err;
306 }
307 break; 305 break;
308 case DSA_PORT_TYPE_DSA: 306 case DSA_PORT_TYPE_DSA:
309 err = dsa_port_link_register_of(dp); 307 err = dsa_port_link_register_of(dp);
310 if (err) { 308 if (err)
311 dev_err(ds->dev, "failed to setup link for port %d.%d\n", 309 dev_err(ds->dev, "failed to setup link for port %d.%d\n",
312 ds->index, dp->index); 310 ds->index, dp->index);
313 return err;
314 }
315 break; 311 break;
316 case DSA_PORT_TYPE_USER: 312 case DSA_PORT_TYPE_USER:
317 err = dsa_slave_create(dp); 313 err = dsa_slave_create(dp);
@@ -323,7 +319,10 @@ static int dsa_port_setup(struct dsa_port *dp)
323 break; 319 break;
324 } 320 }
325 321
326 return 0; 322 if (err)
323 devlink_port_unregister(&dp->devlink_port);
324
325 return err;
327} 326}
328 327
329static void dsa_port_teardown(struct dsa_port *dp) 328static void dsa_port_teardown(struct dsa_port *dp)
@@ -351,7 +350,7 @@ static void dsa_port_teardown(struct dsa_port *dp)
351 350
352static int dsa_switch_setup(struct dsa_switch *ds) 351static int dsa_switch_setup(struct dsa_switch *ds)
353{ 352{
354 int err; 353 int err = 0;
355 354
356 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus 355 /* Initialize ds->phys_mii_mask before registering the slave MDIO bus
357 * driver and before ops->setup() has run, since the switch drivers and 356 * driver and before ops->setup() has run, since the switch drivers and
@@ -369,29 +368,41 @@ static int dsa_switch_setup(struct dsa_switch *ds)
369 368
370 err = devlink_register(ds->devlink, ds->dev); 369 err = devlink_register(ds->devlink, ds->dev);
371 if (err) 370 if (err)
372 return err; 371 goto free_devlink;
373 372
374 err = dsa_switch_register_notifier(ds); 373 err = dsa_switch_register_notifier(ds);
375 if (err) 374 if (err)
376 return err; 375 goto unregister_devlink;
377 376
378 err = ds->ops->setup(ds); 377 err = ds->ops->setup(ds);
379 if (err < 0) 378 if (err < 0)
380 return err; 379 goto unregister_notifier;
381 380
382 if (!ds->slave_mii_bus && ds->ops->phy_read) { 381 if (!ds->slave_mii_bus && ds->ops->phy_read) {
383 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); 382 ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
384 if (!ds->slave_mii_bus) 383 if (!ds->slave_mii_bus) {
385 return -ENOMEM; 384 err = -ENOMEM;
385 goto unregister_notifier;
386 }
386 387
387 dsa_slave_mii_bus_init(ds); 388 dsa_slave_mii_bus_init(ds);
388 389
389 err = mdiobus_register(ds->slave_mii_bus); 390 err = mdiobus_register(ds->slave_mii_bus);
390 if (err < 0) 391 if (err < 0)
391 return err; 392 goto unregister_notifier;
392 } 393 }
393 394
394 return 0; 395 return 0;
396
397unregister_notifier:
398 dsa_switch_unregister_notifier(ds);
399unregister_devlink:
400 devlink_unregister(ds->devlink);
401free_devlink:
402 devlink_free(ds->devlink);
403 ds->devlink = NULL;
404
405 return err;
395} 406}
396 407
397static void dsa_switch_teardown(struct dsa_switch *ds) 408static void dsa_switch_teardown(struct dsa_switch *ds)
@@ -413,8 +424,8 @@ static int dsa_tree_setup_switches(struct dsa_switch_tree *dst)
413{ 424{
414 struct dsa_switch *ds; 425 struct dsa_switch *ds;
415 struct dsa_port *dp; 426 struct dsa_port *dp;
416 int device, port; 427 int device, port, i;
417 int err; 428 int err = 0;
418 429
419 for (device = 0; device < DSA_MAX_SWITCHES; device++) { 430 for (device = 0; device < DSA_MAX_SWITCHES; device++) {
420 ds = dst->ds[device]; 431 ds = dst->ds[device];
@@ -423,18 +434,41 @@ static int dsa_tree_setup_switches(struct dsa_switch_tree *dst)
423 434
424 err = dsa_switch_setup(ds); 435 err = dsa_switch_setup(ds);
425 if (err) 436 if (err)
426 return err; 437 goto switch_teardown;
427 438
428 for (port = 0; port < ds->num_ports; port++) { 439 for (port = 0; port < ds->num_ports; port++) {
429 dp = &ds->ports[port]; 440 dp = &ds->ports[port];
430 441
431 err = dsa_port_setup(dp); 442 err = dsa_port_setup(dp);
432 if (err) 443 if (err)
433 return err; 444 goto ports_teardown;
434 } 445 }
435 } 446 }
436 447
437 return 0; 448 return 0;
449
450ports_teardown:
451 for (i = 0; i < port; i++)
452 dsa_port_teardown(&ds->ports[i]);
453
454 dsa_switch_teardown(ds);
455
456switch_teardown:
457 for (i = 0; i < device; i++) {
458 ds = dst->ds[i];
459 if (!ds)
460 continue;
461
462 for (port = 0; port < ds->num_ports; port++) {
463 dp = &ds->ports[port];
464
465 dsa_port_teardown(dp);
466 }
467
468 dsa_switch_teardown(ds);
469 }
470
471 return err;
438} 472}
439 473
440static void dsa_tree_teardown_switches(struct dsa_switch_tree *dst) 474static void dsa_tree_teardown_switches(struct dsa_switch_tree *dst)
@@ -496,17 +530,24 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst)
496 530
497 err = dsa_tree_setup_switches(dst); 531 err = dsa_tree_setup_switches(dst);
498 if (err) 532 if (err)
499 return err; 533 goto teardown_default_cpu;
500 534
501 err = dsa_tree_setup_master(dst); 535 err = dsa_tree_setup_master(dst);
502 if (err) 536 if (err)
503 return err; 537 goto teardown_switches;
504 538
505 dst->setup = true; 539 dst->setup = true;
506 540
507 pr_info("DSA: tree %d setup\n", dst->index); 541 pr_info("DSA: tree %d setup\n", dst->index);
508 542
509 return 0; 543 return 0;
544
545teardown_switches:
546 dsa_tree_teardown_switches(dst);
547teardown_default_cpu:
548 dsa_tree_teardown_default_cpu(dst);
549
550 return err;
510} 551}
511 552
512static void dsa_tree_teardown(struct dsa_switch_tree *dst) 553static void dsa_tree_teardown(struct dsa_switch_tree *dst)
@@ -547,8 +588,10 @@ static int dsa_tree_add_switch(struct dsa_switch_tree *dst,
547 dst->ds[index] = ds; 588 dst->ds[index] = ds;
548 589
549 err = dsa_tree_setup(dst); 590 err = dsa_tree_setup(dst);
550 if (err) 591 if (err) {
551 dsa_tree_remove_switch(dst, index); 592 dst->ds[index] = NULL;
593 dsa_tree_put(dst);
594 }
552 595
553 return err; 596 return err;
554} 597}