Commit 0dbc1b4a authored by Eli Cohen's avatar Eli Cohen Committed by Michael S. Tsirkin
Browse files

vdpa/mlx5: Avoid using reslock in event_handler



event_handler runs under atomic context and may not acquire reslock. We
can still guarantee that the handler won't be called after suspend by
clearing nb_registered, unregistering the handler and flushing the
workqueue.

Signed-off-by: default avatarEli Cohen <elic@nvidia.com>
Message-Id: <20221114131759.57883-5-elic@nvidia.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent 1ab53760
Loading
Loading
Loading
Loading
+4 −12
Original line number Diff line number Diff line
@@ -2845,8 +2845,8 @@ static int mlx5_vdpa_suspend(struct vdpa_device *vdev)
	int i;

	down_write(&ndev->reslock);
	mlx5_notifier_unregister(mvdev->mdev, &ndev->nb);
	ndev->nb_registered = false;
	mlx5_notifier_unregister(mvdev->mdev, &ndev->nb);
	flush_workqueue(ndev->mvdev.wq);
	for (i = 0; i < ndev->cur_num_vqs; i++) {
		mvq = &ndev->vqs[i];
@@ -3024,7 +3024,7 @@ static void update_carrier(struct work_struct *work)
	else
		ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP);

	if (ndev->config_cb.callback)
	if (ndev->nb_registered && ndev->config_cb.callback)
		ndev->config_cb.callback(ndev->config_cb.private);

	kfree(wqent);
@@ -3041,21 +3041,13 @@ static int event_handler(struct notifier_block *nb, unsigned long event, void *p
		switch (eqe->sub_type) {
		case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
		case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
			down_read(&ndev->reslock);
			if (!ndev->nb_registered) {
				up_read(&ndev->reslock);
				return NOTIFY_DONE;
			}
			wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC);
			if (!wqent) {
				up_read(&ndev->reslock);
			if (!wqent)
				return NOTIFY_DONE;
			}

			wqent->mvdev = &ndev->mvdev;
			INIT_WORK(&wqent->work, update_carrier);
			queue_work(ndev->mvdev.wq, &wqent->work);
			up_read(&ndev->reslock);
			ret = NOTIFY_OK;
			break;
		default:
@@ -3242,8 +3234,8 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *
	struct workqueue_struct *wq;

	if (ndev->nb_registered) {
		mlx5_notifier_unregister(mvdev->mdev, &ndev->nb);
		ndev->nb_registered = false;
		mlx5_notifier_unregister(mvdev->mdev, &ndev->nb);
	}
	wq = mvdev->wq;
	mvdev->wq = NULL;