Skip to content

Commit 42ea37b

Browse files
author
Paolo Abeni
committed
Merge branch 'net-mana-fix-probe-remove-error-path-bugs'
Erni Sri Satya Vennela says: ==================== net: mana: Fix probe/remove error path bugs Fix five bugs in mana_probe()/mana_remove() error handling that can cause warnings on uninitialized work structs, NULL pointer dereferences, masked errors, and resource leaks when early probe steps fail. Patches 1-2 move work struct initialization (link_change_work and gf_stats_work) to before any error path that could trigger mana_remove(), preventing WARN_ON in __flush_work() or debug object warnings when sync cancellation runs on uninitialized work structs. Patch 3 guards mana_remove() against double invocation. If PM resume fails, mana_probe() calls mana_remove() which sets gdma_context and driver_data to NULL. A failed resume does not unbind the driver, so when the device is eventually unbound, mana_remove() is called again and dereferences NULL, causing a kernel panic. An early return on NULL gdma_context or driver_data makes the second call harmless. Patch 4 prevents add_adev() from overwriting a port probe error, which could leave the driver in a broken state with NULL ports while reporting success. Patch 5 changes 'goto out' to 'break' in mana_remove()'s port loop so that mana_destroy_eq() is always reached, preventing EQ leaks when a NULL port is encountered. ==================== Link: https://patch.msgid.link/20260420124741.1056179-1-ernis@linux.microsoft.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents 7079c8c + 65267c9 commit 42ea37b

1 file changed

Lines changed: 20 additions & 15 deletions

File tree

drivers/net/ethernet/microsoft/mana/mana_en.c

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3631,8 +3631,12 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
36313631

36323632
ac->gdma_dev = gd;
36333633
gd->driver_data = ac;
3634+
3635+
INIT_WORK(&ac->link_change_work, mana_link_state_handle);
36343636
}
36353637

3638+
INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler);
3639+
36363640
err = mana_create_eq(ac);
36373641
if (err) {
36383642
dev_err(dev, "Failed to create EQs: %d\n", err);
@@ -3648,8 +3652,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
36483652

36493653
if (!resuming) {
36503654
ac->num_ports = num_ports;
3651-
3652-
INIT_WORK(&ac->link_change_work, mana_link_state_handle);
36533655
} else {
36543656
if (ac->num_ports != num_ports) {
36553657
dev_err(dev, "The number of vPorts changed: %d->%d\n",
@@ -3678,10 +3680,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
36783680
if (!resuming) {
36793681
for (i = 0; i < ac->num_ports; i++) {
36803682
err = mana_probe_port(ac, i, &ac->ports[i]);
3681-
/* we log the port for which the probe failed and stop
3682-
* probes for subsequent ports.
3683-
* Note that we keep running ports, for which the probes
3684-
* were successful, unless add_adev fails too
3683+
/* Log the port for which the probe failed, stop probing
3684+
* subsequent ports, and skip add_adev.
3685+
* mana_remove() will clean up already-probed ports.
36853686
*/
36863687
if (err) {
36873688
dev_err(dev, "Probe Failed for port %d\n", i);
@@ -3695,10 +3696,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
36953696
enable_work(&apc->queue_reset_work);
36963697
err = mana_attach(ac->ports[i]);
36973698
rtnl_unlock();
3698-
/* we log the port for which the attach failed and stop
3699-
* attach for subsequent ports
3700-
* Note that we keep running ports, for which the attach
3701-
* were successful, unless add_adev fails too
3699+
/* Log the port for which the attach failed, stop
3700+
* attaching subsequent ports, and skip add_adev.
3701+
* mana_remove() will clean up already-attached ports.
37023702
*/
37033703
if (err) {
37043704
dev_err(dev, "Attach Failed for port %d\n", i);
@@ -3707,9 +3707,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
37073707
}
37083708
}
37093709

3710-
err = add_adev(gd, "eth");
3710+
if (!err)
3711+
err = add_adev(gd, "eth");
37113712

3712-
INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler);
37133713
schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD);
37143714

37153715
out:
@@ -3730,11 +3730,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
37303730
struct gdma_context *gc = gd->gdma_context;
37313731
struct mana_context *ac = gd->driver_data;
37323732
struct mana_port_context *apc;
3733-
struct device *dev = gc->dev;
3733+
struct device *dev;
37343734
struct net_device *ndev;
37353735
int err;
37363736
int i;
37373737

3738+
if (!gc || !ac)
3739+
return;
3740+
3741+
dev = gc->dev;
3742+
37383743
disable_work_sync(&ac->link_change_work);
37393744
cancel_delayed_work_sync(&ac->gf_stats_work);
37403745

@@ -3747,7 +3752,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
37473752
if (!ndev) {
37483753
if (i == 0)
37493754
dev_err(dev, "No net device to remove\n");
3750-
goto out;
3755+
break;
37513756
}
37523757

37533758
apc = netdev_priv(ndev);
@@ -3778,7 +3783,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
37783783
}
37793784

37803785
mana_destroy_eq(ac);
3781-
out:
3786+
37823787
if (ac->per_port_queue_reset_wq) {
37833788
destroy_workqueue(ac->per_port_queue_reset_wq);
37843789
ac->per_port_queue_reset_wq = NULL;

0 commit comments

Comments
 (0)