Linux PCI subsystem development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Tariq Toukan" <tariqt@nvidia.com>
Cc: linux-pci@vger.kernel.org, linux-rdma@vger.kernel.org
Subject: Re: [PATCH net V2 3/4] {RDMA,net}/mlx5: notify IB uplink on LAG aggregate speed change
Date: Fri, 23 Oct 2026 19:32:04 +0000	[thread overview]
Message-ID: <sashiko-outbox-183122@kernel.org> (raw)
In-Reply-To: <20261022193053.3815866-4-tariqt@nvidia.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] RDMA/mlx5: use-after-free of ib_device from lag_event() on teardown
- [Medium] net/mlx5: LAG speed change notified before updating eswitch vport speeds
--

commit 5dd9a6a9f1014a459afa674b27b22373d933dc51
Author: Or Har-Toov <ohartoov@nvidia.com>

{RDMA,net}/mlx5: notify IB uplink on LAG aggregate speed change

This commit adds MLX5_DRIVER_EVENT_LAG_SPEED_CHANGE to notify the mlx5 IB
driver when the cached LAG aggregate speed changes, dispatching
IB_EVENT_DEVICE_SPEED_CHANGE to RDMA consumers.

> diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
> index 6594d38cf1993..cfa7c7ba2b737 100644
> --- a/drivers/infiniband/hw/mlx5/main.c
> +++ b/drivers/infiniband/hw/mlx5/main.c
> @@ -3690,6 +3690,16 @@ static int lag_event(struct notifier_block *nb, unsigned long event, void *data)
>  			rdma_roce_rescan_port(ibdev, portnum + 1);
>  		}
>  		break;
> +	case MLX5_DRIVER_EVENT_LAG_SPEED_CHANGE: {
> +		struct ib_event speed_event = {};
> +
> +		if (!dev->ib_active)
> +			break;
> +		speed_event.device = ibdev;
> +		speed_event.event = IB_EVENT_DEVICE_SPEED_CHANGE;
> +		ib_dispatch_event(&speed_event);
> +		break;
> +	}

[Severity: High]
Can this race with __mlx5_ib_remove() and cause a use-after-free of
struct ib_device on ib_wq?

In drivers/infiniband/core/cache.c, ib_dispatch_event() does not deliver
the event synchronously inside lag_event(). Instead, it queues a work item
with an unreferenced pointer to ibdev onto ib_wq:

drivers/infiniband/core/cache.c:ib_dispatch_event() {
	...
	INIT_WORK(&work->work, ib_generic_event_task);

	work->event = *event;
	...
	queue_work(ib_wq, &work->work);
}

The RDMA core drains ib_wq during ib_unregister_device() via
__ib_unregister_device() -> ib_cache_cleanup_one() ->
flush_workqueue(ib_wq), which runs in MLX5_IB_STAGE_IB_REG cleanup.

However, in drivers/infiniband/hw/mlx5/main.c, dev->lag_events is
unregistered in mlx5_eth_lag_cleanup() under MLX5_IB_STAGE_ROCE, which is
an earlier stage than MLX5_IB_STAGE_IB_REG and therefore runs after
MLX5_IB_STAGE_IB_REG during the reverse-order teardown loop in
__mlx5_ib_remove():

drivers/infiniband/hw/mlx5/main.c:__mlx5_ib_remove() {
	dev->ib_active = false;

	/* Number of stages to cleanup */
	while (stage) {
		stage--;
		if (profile->stage[stage].cleanup)
			profile->stage[stage].cleanup(dev);
	}

	kfree(dev->port);
	ib_dealloc_device(&dev->ib_dev);
}

If lag_event() on ldev->wq checks dev->ib_active just before
__mlx5_ib_remove() sets dev->ib_active = false, __mlx5_ib_remove() can
complete MLX5_IB_STAGE_IB_REG cleanup (including flush_workqueue(ib_wq))
before lag_event() calls ib_dispatch_event(&speed_event).

When MLX5_IB_STAGE_ROCE cleanup then calls mlx5_eth_lag_cleanup() ->
mlx5e_lag_event_unregister() -> blocking_notifier_chain_unregister(), it
only waits for lag_event() to finish queuing the work item, not for ib_wq
to execute it. __mlx5_ib_remove() then calls ib_dealloc_device(&dev->ib_dev)
while ib_generic_event_task() is still pending on ib_wq, so
ib_generic_event_task() -> ib_dispatch_event_clients() in
drivers/infiniband/core/device.c can dereference event->device after it has
been freed.

>  	default:
>  		return NOTIFY_DONE;
>  	}
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
> index 05e6d0aa31fcf..afe0b9909f2dc 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
> @@ -1540,8 +1540,24 @@ static int mlx5_lag_get_devices_oper_speed(struct mlx5_lag *ldev,
>  	return 0;
>  }
>  
> +void mlx5_lag_notify_speed_change(struct mlx5_lag *ldev)
> +{
> +	struct lag_func *pf;
> +	int idx;
> +
> +	idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
> +	if (idx < 0)
> +		return;
> +	pf = mlx5_lag_pf(ldev, idx);
> +	if (!pf)
> +		return;
> +	blocking_notifier_call_chain(&pf->dev->priv.lag_nh,
> +				     MLX5_DRIVER_EVENT_LAG_SPEED_CHANGE, NULL);
> +}
> +
>  int mlx5_lag_update_agg_speed(struct mlx5_lag *ldev)
>  {
> +	u32 old_speed;
>  	u32 speed;
>  	int err;
>  
> @@ -1553,7 +1569,11 @@ int mlx5_lag_update_agg_speed(struct mlx5_lag *ldev)
>  		return err;
>  	}
>  
> +	old_speed = READ_ONCE(ldev->agg_speed_mbps);
>  	WRITE_ONCE(ldev->agg_speed_mbps, speed);
> +	if (speed != old_speed)
> +		mlx5_lag_notify_speed_change(ldev);
> +
>  	return 0;
>  }

[Severity: Medium]
In switchdev mode, does notifying here fire IB_EVENT_DEVICE_SPEED_CHANGE
before the eswitch vport speeds have been updated in firmware?

In drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c,
mlx5_lag_set_vports_agg_speed() calls mlx5_lag_update_agg_speed() before
iterating over the PFs to update the vport speeds via
mlx5_lag_modify_device_vports_speed():

drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c:mlx5_lag_set_vports_agg_speed() {
	if (mlx5_lag_update_agg_speed(ldev))
		return;
	...
	mlx5_ldev_for_each(pf_idx, 0, ldev) {
		...
		mlx5_lag_modify_device_vports_speed(mdev, speed);
	}
}

On the switchdev representor ib_device, mlx5_ib_query_port_speed_rep() in
drivers/infiniband/hw/mlx5/main.c only reads the cached bond speed for the
uplink representor port, while non-uplink VF/SF representor ports on the
same ib_device query MLX5_VPORT_STATE_OP_MOD_ESW_VPORT from firmware:

drivers/infiniband/hw/mlx5/main.c:mlx5_ib_query_port_speed_rep() {
	if (rep->vport == MLX5_VPORT_UPLINK) {
		if (mlx5_lag_is_sriov(mdev))
			return mlx5_ib_query_port_speed_from_bond(dev,
								  port_num,
								  speed);

		return mlx5_ib_query_port_speed_from_port(dev, port_num,
							  speed);
	}

	op_mod = MLX5_VPORT_STATE_OP_MOD_ESW_VPORT;
	return mlx5_ib_query_port_speed_from_vport(dev->mdev, op_mod,
						   rep->vport, true, speed, dev,
						   port_num);
}

If a consumer of the switchdev representor ib_device queries port speeds
upon receiving IB_EVENT_DEVICE_SPEED_CHANGE, could non-uplink representor
ports still return the old max_tx_speed from firmware because
mlx5_lag_modify_device_vports_speed() has not finished yet?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261022193053.3815866-1-tariqt@nvidia.com?part=3

  reply	other threads:[~2026-10-23 19:32 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-22 19:30 [PATCH net V2 0/4] net/mlx5: fixes for LAG max_tx_speed update flow Tariq Toukan
2026-10-22 19:30 ` [PATCH net V2 1/4] {RDMA,net}/mlx5: cache and use TX-enabled aggregate speed for vports Tariq Toukan
2026-10-23 19:32   ` sashiko-bot
2026-10-26 20:32   ` netdev-bot+sashiko
2026-10-22 19:30 ` [PATCH net V2 2/4] net/mlx5: Lag, limit aggregated TX speed by PCIe bandwidth Tariq Toukan
2026-10-23 19:32   ` sashiko-bot
2026-10-23 20:06   ` Bjorn Helgaas
2026-10-26 20:32   ` netdev-bot+sashiko
2026-10-22 19:30 ` [PATCH net V2 3/4] {RDMA,net}/mlx5: notify IB uplink on LAG aggregate speed change Tariq Toukan
2026-10-23 19:32   ` sashiko-bot [this message]
2026-10-26 20:32   ` netdev-bot+sashiko
2026-10-22 19:30 ` [PATCH net V2 4/4] net/mlx5: Lag, save and restore vport max_tx_speed across LAG Tariq Toukan
2026-10-23 19:32   ` sashiko-bot
2026-10-26 20:32   ` netdev-bot+sashiko
2026-10-22 19:37 ` [PATCH net V2 0/4] net/mlx5: fixes for LAG max_tx_speed update flow netdev-bot+sinfo
2026-10-25 14:59   ` Or Har-Toov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-183122@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tariqt@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox