diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 8563fec2855d..0fcb18b5f30a 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -3059,7 +3059,15 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, bool teardown = !is_resumable(ndev); int err; - suspend_vqs(ndev, 0, ndev->cur_num_vqs); + if ((mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && !mvdev->suspended) { + err = suspend_vqs(ndev, 0, ndev->cur_num_vqs); + if (err && !teardown) { + for (int i = 0; i < ndev->cur_num_vqs; i++) + resume_vqs(ndev, i, 1); + mlx5_vdpa_put_mr(mvdev, new_mr); + return err; + } + } if (teardown) { err = save_channels_info(ndev); if (err) { diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 017366cb6684..97d437d89524 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -638,6 +638,7 @@ static int vdpasim_set_map(struct vdpa_device *vdpa, unsigned int asid, if (asid >= vdpasim->dev_attr.nas) return -EINVAL; + mutex_lock(&vdpasim->mutex); spin_lock(&vdpasim->iommu_lock); iommu = &vdpasim->iommu[asid]; @@ -652,11 +653,13 @@ static int vdpasim_set_map(struct vdpa_device *vdpa, unsigned int asid, goto err; } spin_unlock(&vdpasim->iommu_lock); + mutex_unlock(&vdpasim->mutex); return 0; err: vhost_iotlb_reset(iommu); spin_unlock(&vdpasim->iommu_lock); + mutex_unlock(&vdpasim->mutex); return ret; } diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 43678124646a..ad3a157b4050 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -998,10 +998,10 @@ static void vhost_vdpa_va_unmap(struct vhost_vdpa *v, struct vhost_iotlb *iotlb, struct vdpa_map_file *map_file; while ((map = vhost_iotlb_itree_first(iotlb, start, last)) != NULL) { + vhost_vdpa_general_unmap(v, map, asid); map_file = (struct vdpa_map_file *)map->opaque; fput(map_file->file); kfree(map_file); - vhost_vdpa_general_unmap(v, map, asid); vhost_iotlb_map_free(iotlb, map); } } @@ -1075,21 +1075,39 @@ static int vhost_vdpa_map(struct vhost_vdpa *v, struct vhost_iotlb *iotlb, return 0; } -static void vhost_vdpa_unmap(struct vhost_vdpa *v, - struct vhost_iotlb *iotlb, - u64 iova, u64 size) +static int vhost_vdpa_unmap(struct vhost_vdpa *v, + struct vhost_iotlb *iotlb, + u64 iova, u64 size) { struct vdpa_device *vdpa = v->vdpa; const struct vdpa_config_ops *ops = vdpa->config; + struct vhost_iotlb_map *map; + struct vhost_iotlb new_iotlb; u32 asid = iotlb_to_asid(iotlb); + u64 last = iova + size - 1; + int ret; - vhost_vdpa_iotlb_unmap(v, iotlb, iova, iova + size - 1, asid); + if (ops->set_map && !ops->dma_map) { + vhost_iotlb_init(&new_iotlb, iotlb->limit, iotlb->flags); + list_for_each_entry(map, &iotlb->list, link) { + if (map->start <= last && map->last >= iova) + continue; + ret = vhost_iotlb_add_range_ctx(&new_iotlb, map->start, + map->last, map->addr, + map->perm, map->opaque); + if (ret) + goto reset; + } - if (ops->set_map) { - if (!v->in_batch) - ops->set_map(vdpa, asid, iotlb); + ret = ops->set_map(vdpa, asid, &new_iotlb); +reset: + vhost_iotlb_reset(&new_iotlb); + if (ret) + return ret; } + vhost_vdpa_iotlb_unmap(v, iotlb, iova, last, asid); + return 0; } static int vhost_vdpa_va_map(struct vhost_vdpa *v, @@ -1343,7 +1361,11 @@ static int vhost_vdpa_process_iotlb_msg(struct vhost_dev *dev, u32 asid, r = vhost_vdpa_process_iotlb_update(v, iotlb, msg); break; case VHOST_IOTLB_INVALIDATE: - vhost_vdpa_unmap(v, iotlb, msg->iova, msg->size); + if (!msg->size || msg->iova > U64_MAX - msg->size + 1) { + r = -EINVAL; + break; + } + r = vhost_vdpa_unmap(v, iotlb, msg->iova, msg->size); break; case VHOST_IOTLB_BATCH_BEGIN: v->batch_asid = asid;