Commit 06be3029 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull virtio fixes from Michael Tsirkin:
 "Some last minute fixes that took a while to get ready. Not
  regressions, but they look safe and seem to be worth to have"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
  tools/virtio: handle fallout from folio work
  tools/virtio: fix virtio_test execution
  vhost: remove avail_event arg from vhost_update_avail_event()
  virtio: drop default for virtio-mem
  vdpa: fix use-after-free on vp_vdpa_remove
  virtio-blk: Remove BUG_ON() in virtio_queue_rq()
  virtio-blk: Don't use MAX_DISCARD_SEGMENTS if max_discard_seg is zero
  vhost: fix hung thread due to erroneous iotlb entries
  vduse: Fix returning wrong type in vduse_domain_alloc_iova()
  vdpa/mlx5: add validation for VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET command
  vdpa/mlx5: should verify CTRL_VQ feature exists for MQ
  vdpa: factor out vdpa_set_features_unlocked for vdpa internal use
  virtio_console: break out of buf poll on remove
  virtio: document virtio_reset_device
  virtio: acknowledge all features before access
  virtio: unexport virtio_finalize_features
parents aa6f8dcb 3dd7d135
Loading
Loading
Loading
Loading
+9 −11
Original line number Diff line number Diff line
@@ -76,9 +76,6 @@ struct virtio_blk {
	 */
	refcount_t refs;

	/* What host tells us, plus 2 for header & tailer. */
	unsigned int sg_elems;

	/* Ida index - used to track minor number allocations. */
	int index;

@@ -322,8 +319,6 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
	blk_status_t status;
	int err;

	BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);

	status = virtblk_setup_cmd(vblk->vdev, req, vbr);
	if (unlikely(status))
		return status;
@@ -783,8 +778,6 @@ static int virtblk_probe(struct virtio_device *vdev)
	/* Prevent integer overflows and honor max vq size */
	sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);

	/* We need extra sg elements at head and tail. */
	sg_elems += 2;
	vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
	if (!vblk) {
		err = -ENOMEM;
@@ -796,7 +789,6 @@ static int virtblk_probe(struct virtio_device *vdev)
	mutex_init(&vblk->vdev_mutex);

	vblk->vdev = vdev;
	vblk->sg_elems = sg_elems;

	INIT_WORK(&vblk->config_work, virtblk_config_changed_work);

@@ -853,7 +845,7 @@ static int virtblk_probe(struct virtio_device *vdev)
		set_disk_ro(vblk->disk, 1);

	/* We can handle whatever the host told us to handle. */
	blk_queue_max_segments(q, vblk->sg_elems-2);
	blk_queue_max_segments(q, sg_elems);

	/* No real sector limit. */
	blk_queue_max_hw_sectors(q, -1U);
@@ -925,9 +917,15 @@ static int virtblk_probe(struct virtio_device *vdev)

		virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
			     &v);

		/*
		 * max_discard_seg == 0 is out of spec but we always
		 * handled it.
		 */
		if (!v)
			v = sg_elems;
		blk_queue_max_discard_segments(q,
					       min_not_zero(v,
							    MAX_DISCARD_SEGMENTS));
					       min(v, MAX_DISCARD_SEGMENTS));

		blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
	}
+7 −0
Original line number Diff line number Diff line
@@ -1957,6 +1957,13 @@ static void virtcons_remove(struct virtio_device *vdev)
	list_del(&portdev->list);
	spin_unlock_irq(&pdrvdata_lock);

	/* Device is going away, exit any polling for buffers */
	virtio_break_device(vdev);
	if (use_multiport(portdev))
		flush_work(&portdev->control_work);
	else
		flush_work(&portdev->config_work);

	/* Disable interrupts for vqs */
	virtio_reset_device(vdev);
	/* Finish up work that's lined up */
+32 −2
Original line number Diff line number Diff line
@@ -1563,11 +1563,27 @@ static virtio_net_ctrl_ack handle_ctrl_mq(struct mlx5_vdpa_dev *mvdev, u8 cmd)

	switch (cmd) {
	case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET:
		/* This mq feature check aligns with pre-existing userspace
		 * implementation.
		 *
		 * Without it, an untrusted driver could fake a multiqueue config
		 * request down to a non-mq device that may cause kernel to
		 * panic due to uninitialized resources for extra vqs. Even with
		 * a well behaving guest driver, it is not expected to allow
		 * changing the number of vqs on a non-mq device.
		 */
		if (!MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ))
			break;

		read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)&mq, sizeof(mq));
		if (read != sizeof(mq))
			break;

		newqps = mlx5vdpa16_to_cpu(mvdev, mq.virtqueue_pairs);
		if (newqps < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
		    newqps > mlx5_vdpa_max_qps(mvdev->max_vqs))
			break;

		if (ndev->cur_num_vqs == 2 * newqps) {
			status = VIRTIO_NET_OK;
			break;
@@ -1897,11 +1913,25 @@ static u64 mlx5_vdpa_get_device_features(struct vdpa_device *vdev)
	return ndev->mvdev.mlx_features;
}

static int verify_min_features(struct mlx5_vdpa_dev *mvdev, u64 features)
static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features)
{
	/* Minimum features to expect */
	if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)))
		return -EOPNOTSUPP;

	/* Double check features combination sent down by the driver.
	 * Fail invalid features due to absence of the depended feature.
	 *
	 * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit
	 * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ".
	 * By failing the invalid features sent down by untrusted drivers,
	 * we're assured the assumption made upon is_index_valid() and
	 * is_ctrl_vq_idx() will not be compromised.
	 */
	if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) ==
            BIT_ULL(VIRTIO_NET_F_MQ))
		return -EINVAL;

	return 0;
}

@@ -1977,7 +2007,7 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features)

	print_features(mvdev, features, true);

	err = verify_min_features(mvdev, features);
	err = verify_driver_features(mvdev, features);
	if (err)
		return err;

+1 −1
Original line number Diff line number Diff line
@@ -393,7 +393,7 @@ static void vdpa_get_config_unlocked(struct vdpa_device *vdev,
	 * If it does happen we assume a legacy guest.
	 */
	if (!vdev->features_valid)
		vdpa_set_features(vdev, 0, true);
		vdpa_set_features_unlocked(vdev, 0);
	ops->get_config(vdev, offset, buf, len);
}

+1 −1
Original line number Diff line number Diff line
@@ -294,7 +294,7 @@ vduse_domain_alloc_iova(struct iova_domain *iovad,

	iova_pfn = alloc_iova_fast(iovad, iova_len, limit >> shift, true);

	return iova_pfn << shift;
	return (dma_addr_t)iova_pfn << shift;
}

static void vduse_domain_free_iova(struct iova_domain *iovad,
Loading