Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+20 -15
+20 -15
drivers/net/ethernet/microsoft/mana/mana_en.c
··· 3631 3631 3632 3632 ac->gdma_dev = gd; 3633 3633 gd->driver_data = ac; 3634 + 3635 + INIT_WORK(&ac->link_change_work, mana_link_state_handle); 3634 3636 } 3637 + 3638 + INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler); 3635 3639 3636 3640 err = mana_create_eq(ac); 3637 3641 if (err) { ··· 3652 3648 3653 3649 if (!resuming) { 3654 3650 ac->num_ports = num_ports; 3655 - 3656 - INIT_WORK(&ac->link_change_work, mana_link_state_handle); 3657 3651 } else { 3658 3652 if (ac->num_ports != num_ports) { 3659 3653 dev_err(dev, "The number of vPorts changed: %d->%d\n", ··· 3680 3678 if (!resuming) { 3681 3679 for (i = 0; i < ac->num_ports; i++) { 3682 3680 err = mana_probe_port(ac, i, &ac->ports[i]); 3683 - /* we log the port for which the probe failed and stop 3684 - * probes for subsequent ports. 3685 - * Note that we keep running ports, for which the probes 3686 - * were successful, unless add_adev fails too 3681 + /* Log the port for which the probe failed, stop probing 3682 + * subsequent ports, and skip add_adev. 3683 + * mana_remove() will clean up already-probed ports. 3687 3684 */ 3688 3685 if (err) { 3689 3686 dev_err(dev, "Probe Failed for port %d\n", i); ··· 3696 3695 enable_work(&apc->queue_reset_work); 3697 3696 err = mana_attach(ac->ports[i]); 3698 3697 rtnl_unlock(); 3699 - /* we log the port for which the attach failed and stop 3700 - * attach for subsequent ports 3701 - * Note that we keep running ports, for which the attach 3702 - * were successful, unless add_adev fails too 3698 + /* Log the port for which the attach failed, stop 3699 + * attaching subsequent ports, and skip add_adev. 3700 + * mana_remove() will clean up already-attached ports. 3703 3701 */ 3704 3702 if (err) { 3705 3703 dev_err(dev, "Attach Failed for port %d\n", i); ··· 3707 3707 } 3708 3708 } 3709 3709 3710 - err = add_adev(gd, "eth"); 3710 + if (!err) 3711 + err = add_adev(gd, "eth"); 3711 3712 3712 - INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler); 3713 3713 schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD); 3714 3714 3715 3715 out: ··· 3730 3730 struct gdma_context *gc = gd->gdma_context; 3731 3731 struct mana_context *ac = gd->driver_data; 3732 3732 struct mana_port_context *apc; 3733 - struct device *dev = gc->dev; 3733 + struct device *dev; 3734 3734 struct net_device *ndev; 3735 3735 int err; 3736 3736 int i; 3737 + 3738 + if (!gc || !ac) 3739 + return; 3740 + 3741 + dev = gc->dev; 3737 3742 3738 3743 disable_work_sync(&ac->link_change_work); 3739 3744 cancel_delayed_work_sync(&ac->gf_stats_work); ··· 3752 3747 if (!ndev) { 3753 3748 if (i == 0) 3754 3749 dev_err(dev, "No net device to remove\n"); 3755 - goto out; 3750 + break; 3756 3751 } 3757 3752 3758 3753 apc = netdev_priv(ndev); ··· 3783 3778 } 3784 3779 3785 3780 mana_destroy_eq(ac); 3786 - out: 3781 + 3787 3782 if (ac->per_port_queue_reset_wq) { 3788 3783 destroy_workqueue(ac->per_port_queue_reset_wq); 3789 3784 ac->per_port_queue_reset_wq = NULL;