Unverified Commit 80659f8a authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!10585 Fix the issue that vm can't access to host with virtio-net

Merge Pull Request from: @cj-xiaocai 
 
使用virtio-net的vm ping不通,业务断网,网络不通的vm 有not a head报错:
/home/gavin/sandbox/qemu.main/build/qemu-system-aarch64
-accel kvm -machine virt,gic-version=host -cpu host
-smp maxcpus=1,cpus=1,sockets=1,clusters=1,cores=1,threads=1
-m 4096M,slots=16,maxmem=64G
-object memory-backend-ram,id=mem0,size=4096M
:
-netdev tap,id=vnet0,vhost=true
-device virtio-net-pci,bus=pcie.8,netdev=vnet0,mac=52:54:00:f1:26:b0
:
guest# netperf -H 10.26.1.81 -l 60 -C -c -t UDP_STREAM
virtio_net virtio0: output.0:id 100 is not a head!

https://gitee.com/openeuler/kernel/issues/IAHGCP

前面已有两个相关patch已合入:
724be72c vhost: Add smp_rmb() in vhost_enable_notify()
cadc88eb vhost: Add smp_rmb() in vhost_vq_avail_empty() 
 
Link:https://gitee.com/openeuler/kernel/pulls/10585

 

Reviewed-by: default avatarZhang Peng <zhangpeng362@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 483a84a9 8a26e883
Loading
Loading
Loading
Loading
+42 −63
Original line number Diff line number Diff line
@@ -1358,10 +1358,36 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d)
		mutex_unlock(&d->vqs[i]->mutex);
}

static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
				      __virtio16 *idx)
static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq)
{
	return vhost_get_avail(vq, *idx, &vq->avail->idx);
	__virtio16 idx;
	int r;

	r = vhost_get_avail(vq, idx, &vq->avail->idx);
	if (unlikely(r < 0)) {
		vq_err(vq, "Failed to access available index at %p (%d)\n",
		       &vq->avail->idx, r);
		return r;
	}

	/* Check it isn't doing very strange thing with available indexes */
	vq->avail_idx = vhost16_to_cpu(vq, idx);
	if (unlikely((u16)(vq->avail_idx - vq->last_avail_idx) > vq->num)) {
		vq_err(vq, "Invalid available index change from %u to %u",
		       vq->last_avail_idx, vq->avail_idx);
		return -EINVAL;
	}

	/* We're done if there is nothing new */
	if (vq->avail_idx == vq->last_avail_idx)
		return 0;

	/*
	 * We updated vq->avail_idx so we need a memory barrier between
	 * the index read above and the caller reading avail ring entries.
	 */
	smp_rmb();
	return 1;
}

static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
@@ -2566,38 +2592,17 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
{
	struct vring_desc desc;
	unsigned int i, head, found = 0;
	u16 last_avail_idx;
	__virtio16 avail_idx;
	u16 last_avail_idx = vq->last_avail_idx;
	__virtio16 ring_head;
	int ret, access;

	/* Check it isn't doing very strange things with descriptor numbers. */
	last_avail_idx = vq->last_avail_idx;

	if (vq->avail_idx == vq->last_avail_idx) {
		if (unlikely(vhost_get_avail_idx(vq, &avail_idx))) {
			vq_err(vq, "Failed to access avail idx at %p\n",
				&vq->avail->idx);
			return -EFAULT;
		}
		vq->avail_idx = vhost16_to_cpu(vq, avail_idx);

		if (unlikely((u16)(vq->avail_idx - last_avail_idx) > vq->num)) {
			vq_err(vq, "Guest moved used index from %u to %u",
				last_avail_idx, vq->avail_idx);
			return -EFAULT;
		}
		ret = vhost_get_avail_idx(vq);
		if (unlikely(ret < 0))
			return ret;

		/* If there's nothing new since last we looked, return
		 * invalid.
		 */
		if (vq->avail_idx == last_avail_idx)
		if (!ret)
			return vq->num;

		/* Only get avail ring entries after they have been
		 * exposed by guest.
		 */
		smp_rmb();
	}

	/* Grab the next descriptor number they're advertising, and increment
@@ -2858,35 +2863,21 @@ EXPORT_SYMBOL_GPL(vhost_add_used_and_signal_n);
/* return true if we're sure that avaiable ring is empty */
bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
	__virtio16 avail_idx;
	int r;

	if (vq->avail_idx != vq->last_avail_idx)
		return false;

	r = vhost_get_avail_idx(vq, &avail_idx);
	if (unlikely(r))
		return false;
	r = vhost_get_avail_idx(vq);

	vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
	if (vq->avail_idx != vq->last_avail_idx) {
		/* Since we have updated avail_idx, the following
		 * call to vhost_get_vq_desc() will read available
		 * ring entries. Make sure that read happens after
		 * the avail_idx read.
		 */
		smp_rmb();
		return false;
	}

	return true;
	/* Note: we treat error as non-empty here */
	return r == 0;
}
EXPORT_SYMBOL_GPL(vhost_vq_avail_empty);

/* OK, now we need to know about added descriptors. */
bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
	__virtio16 avail_idx;
	int r;

	if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
@@ -2910,25 +2901,13 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
	/* They could have slipped one in as we were doing that: make
	 * sure it's written, then check again. */
	smp_mb();
	r = vhost_get_avail_idx(vq, &avail_idx);
	if (r) {
		vq_err(vq, "Failed to check avail idx at %p: %d\n",
		       &vq->avail->idx, r);
		return false;
	}

	vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
	if (vq->avail_idx != vq->last_avail_idx) {
		/* Since we have updated avail_idx, the following
		 * call to vhost_get_vq_desc() will read available
		 * ring entries. Make sure that read happens after
		 * the avail_idx read.
		 */
		smp_rmb();
		return true;
	}

	r = vhost_get_avail_idx(vq);
	/* Note: we treat error as empty here */
	if (unlikely(r < 0))
		return false;

	return r;
}
EXPORT_SYMBOL_GPL(vhost_enable_notify);