Skip to content

Commit 1c80cf0

Browse files
jasowangmstsirkin
authored andcommitted
vdpa: mlx5: synchronize driver status with CVQ
Currently, CVQ doesn't have any synchronization with the driver status. Then CVQ emulation code run in the middle of: 1) device reset 2) device status changed 3) map updating The will lead several unexpected issue like trying to execute CVQ command after the driver has been teared down. Fixing this by using reslock to synchronize CVQ emulation code with the driver status changing: - protect the whole device reset, status changing and set_map() updating with reslock - protect the CVQ handler with the reslock and check VIRTIO_CONFIG_S_DRIVER_OK in the CVQ handler This will guarantee that: 1) CVQ handler won't work if VIRTIO_CONFIG_S_DRIVER_OK is not set 2) CVQ handler will see a consistent state of the driver instead of the partial one when it is running in the middle of the teardown_driver() or setup_driver(). Cc: 5262912 ("vdpa/mlx5: Add support for control VQ and MAC setting") Signed-off-by: Jason Wang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michael S. Tsirkin <[email protected]> Acked-by: Eli Cohen <[email protected]>
1 parent 55ebf0d commit 1c80cf0

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

drivers/vdpa/mlx5/net/mlx5_vnet.c

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,11 +1659,17 @@ static void mlx5_cvq_kick_handler(struct work_struct *work)
16591659
mvdev = wqent->mvdev;
16601660
ndev = to_mlx5_vdpa_ndev(mvdev);
16611661
cvq = &mvdev->cvq;
1662+
1663+
mutex_lock(&ndev->reslock);
1664+
1665+
if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
1666+
goto out;
1667+
16621668
if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ)))
1663-
return;
1669+
goto out;
16641670

16651671
if (!cvq->ready)
1666-
return;
1672+
goto out;
16671673

16681674
while (true) {
16691675
err = vringh_getdesc_iotlb(&cvq->vring, &cvq->riov, &cvq->wiov, &cvq->head,
@@ -1701,6 +1707,9 @@ static void mlx5_cvq_kick_handler(struct work_struct *work)
17011707
queue_work(mvdev->wq, &wqent->work);
17021708
break;
17031709
}
1710+
1711+
out:
1712+
mutex_unlock(&ndev->reslock);
17041713
}
17051714

17061715
static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx)
@@ -2175,7 +2184,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb
21752184
goto err_mr;
21762185

21772186
if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
2178-
return 0;
2187+
goto err_mr;
21792188

21802189
restore_channels_info(ndev);
21812190
err = setup_driver(mvdev);
@@ -2190,12 +2199,14 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb
21902199
return err;
21912200
}
21922201

2202+
/* reslock must be held for this function */
21932203
static int setup_driver(struct mlx5_vdpa_dev *mvdev)
21942204
{
21952205
struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
21962206
int err;
21972207

2198-
mutex_lock(&ndev->reslock);
2208+
WARN_ON(!mutex_is_locked(&ndev->reslock));
2209+
21992210
if (ndev->setup) {
22002211
mlx5_vdpa_warn(mvdev, "setup driver called for already setup driver\n");
22012212
err = 0;
@@ -2225,7 +2236,6 @@ static int setup_driver(struct mlx5_vdpa_dev *mvdev)
22252236
goto err_fwd;
22262237
}
22272238
ndev->setup = true;
2228-
mutex_unlock(&ndev->reslock);
22292239

22302240
return 0;
22312241

@@ -2236,23 +2246,23 @@ static int setup_driver(struct mlx5_vdpa_dev *mvdev)
22362246
err_rqt:
22372247
teardown_virtqueues(ndev);
22382248
out:
2239-
mutex_unlock(&ndev->reslock);
22402249
return err;
22412250
}
22422251

2252+
/* reslock must be held for this function */
22432253
static void teardown_driver(struct mlx5_vdpa_net *ndev)
22442254
{
2245-
mutex_lock(&ndev->reslock);
2255+
2256+
WARN_ON(!mutex_is_locked(&ndev->reslock));
2257+
22462258
if (!ndev->setup)
2247-
goto out;
2259+
return;
22482260

22492261
remove_fwd_to_tir(ndev);
22502262
destroy_tir(ndev);
22512263
destroy_rqt(ndev);
22522264
teardown_virtqueues(ndev);
22532265
ndev->setup = false;
2254-
out:
2255-
mutex_unlock(&ndev->reslock);
22562266
}
22572267

22582268
static void clear_vqs_ready(struct mlx5_vdpa_net *ndev)
@@ -2273,6 +2283,8 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status)
22732283

22742284
print_status(mvdev, status, true);
22752285

2286+
mutex_lock(&ndev->reslock);
2287+
22762288
if ((status ^ ndev->mvdev.status) & VIRTIO_CONFIG_S_DRIVER_OK) {
22772289
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
22782290
err = setup_driver(mvdev);
@@ -2282,16 +2294,19 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status)
22822294
}
22832295
} else {
22842296
mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n");
2285-
return;
2297+
goto err_clear;
22862298
}
22872299
}
22882300

22892301
ndev->mvdev.status = status;
2302+
mutex_unlock(&ndev->reslock);
22902303
return;
22912304

22922305
err_setup:
22932306
mlx5_vdpa_destroy_mr(&ndev->mvdev);
22942307
ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED;
2308+
err_clear:
2309+
mutex_unlock(&ndev->reslock);
22952310
}
22962311

22972312
static int mlx5_vdpa_reset(struct vdpa_device *vdev)
@@ -2301,6 +2316,8 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev)
23012316

23022317
print_status(mvdev, 0, true);
23032318
mlx5_vdpa_info(mvdev, "performing device reset\n");
2319+
2320+
mutex_lock(&ndev->reslock);
23042321
teardown_driver(ndev);
23052322
clear_vqs_ready(ndev);
23062323
mlx5_vdpa_destroy_mr(&ndev->mvdev);
@@ -2313,6 +2330,7 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev)
23132330
if (mlx5_vdpa_create_mr(mvdev, NULL))
23142331
mlx5_vdpa_warn(mvdev, "create MR failed\n");
23152332
}
2333+
mutex_unlock(&ndev->reslock);
23162334

23172335
return 0;
23182336
}
@@ -2348,19 +2366,24 @@ static u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev)
23482366
static int mlx5_vdpa_set_map(struct vdpa_device *vdev, struct vhost_iotlb *iotlb)
23492367
{
23502368
struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
2369+
struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
23512370
bool change_map;
23522371
int err;
23532372

2373+
mutex_lock(&ndev->reslock);
2374+
23542375
err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map);
23552376
if (err) {
23562377
mlx5_vdpa_warn(mvdev, "set map failed(%d)\n", err);
2357-
return err;
2378+
goto err;
23582379
}
23592380

23602381
if (change_map)
2361-
return mlx5_vdpa_change_map(mvdev, iotlb);
2382+
err = mlx5_vdpa_change_map(mvdev, iotlb);
23622383

2363-
return 0;
2384+
err:
2385+
mutex_unlock(&ndev->reslock);
2386+
return err;
23642387
}
23652388

23662389
static void mlx5_vdpa_free(struct vdpa_device *vdev)

0 commit comments

Comments
 (0)