From: Jason Wang <hidden> Date: 2018-12-10 09:45:03
Hi:
This series tries to fix various issues of vhost:
- Patch 1 adds a missing write barrier between used idx updating and
logging.
- Patch 2-3 brings back the protection of device IOTLB through vq
mutex, this fixes possible use after free in device IOTLB entries.
- Patch 4 fixes the diry page logging when device IOTLB is
enabled. We should done through GPA instead of GIOVA, this was done
through logging through iovec and traversing GPA->HPA list for the
GPA.
Please consider them for -stable.
Thanks
Jason Wang (4):
vhost: make sure used idx is seen before log in vhost_add_used_n()
vhost_net: rework on the lock ordering for busy polling
Revert "net: vhost: lock the vqs one by one"
vhost: log dirty page correctly
drivers/vhost/net.c | 21 +++++++--
drivers/vhost/vhost.c | 101 ++++++++++++++++++++++++++++++++++--------
drivers/vhost/vhost.h | 3 +-
3 files changed, 102 insertions(+), 23 deletions(-)
--
2.17.1
From: Jason Wang <hidden> Date: 2018-12-10 09:45:08
We miss a write barrier that guarantees used idx is updated and seen
before log. This will let userspace sync and copy used ring before
used idx is update. Fix this by adding a barrier before log_write().
Fixes: 8dd014adfea6f ("vhost-net: mergeable buffers support")
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 2 ++
1 file changed, 2 insertions(+)
@@ -2220,6 +2220,8 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,return-EFAULT;}if(unlikely(vq->log_used)){+/* Make sure used idx is seen before log. */+smp_wmb();/* Log used index update. */log_write(vq->log_base,vq->log_addr+offsetof(structvring_used,idx),
From: Jason Wang <hidden> Date: 2018-12-10 09:45:16
When we try to do rx busy polling in tx path in commit 441abde4cd84
("net: vhost: add rx busy polling in tx path"), we lock rx vq mutex
after tx vq mutex is held. This may lead deadlock so we try to lock vq
one by one in commit 78139c94dc8c ("net: vhost: lock the vqs one by
one"). With this commit, we avoid the deadlock with the assumption
that handle_rx() and handle_tx() run in a same process. But this
commit remove the protection for IOTLB updating which requires the
mutex of each vq to be held.
To solve this issue, the first step is to have a exact same lock
ordering for vhost_net. This is done through:
- For handle_rx(), if busy polling is enabled, lock tx vq immediately.
- For handle_tx(), always lock rx vq before tx vq, and unlock it if
busy polling is not enabled.
- Remove the tricky locking codes in busy polling.
With this, we can have a exact same lock ordering for vhost_net, this
allows us to safely revert commit 78139c94dc8c ("net: vhost: lock the
vqs one by one") in next patch.
The patch will add two more atomic operations on the tx path during
each round of handle_tx(). 1 byte TCP_RR does not notice such
overhead.
Fixes: commit 78139c94dc8c ("net: vhost: lock the vqs one by one")
Cc: Tonghao Zhang <redacted>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/net.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
From: Jason Wang <hidden> Date: 2018-12-10 09:45:27
This reverts commit 78139c94dc8c96a478e67dab3bee84dc6eccb5fd. We don't
protect device IOTLB with vq mutex, which will lead e.g use after free
for device IOTLB entries. And since we've exact the same lock order
with the help of previous patch, it's safe to revert it without having
deadlock.
Fixes: commit 78139c94dc8c ("net: vhost: lock the vqs one by one")
Cc: Tonghao Zhang <redacted>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
From: Jason Wang <hidden> Date: 2018-12-10 09:45:31
Vhost dirty page logging API is designed to sync through GPA. But we
try to log GIOVA when device IOTLB is enabled. This is wrong and may
lead to missing data after migration.
To solve this issue, when logging with device IOTLB enabled, we will:
1) reuse the device IOTLB translation result of GIOVA->HVA mapping to
get HVA, for writable descriptor, get HVA through iovec. For used
ring update, translate its GIOVA to HVA
2) traverse the GPA->HVA mapping to get the possible GPA and log
through GPA. Pay attention this reverse mapping is not guaranteed
to be unique, so we should log each possible GPA in this case.
This fix the failure of scp to guest during migration. In -next, we
will probably support passing GIOVA->GPA instead of GIOVA->HVA.
Fixes: 6b1e6cc7855b ("vhost: new device IOTLB API")
Reported-by: Jintack Lim <redacted>
Cc: Jintack Lim <redacted>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/net.c | 3 +-
drivers/vhost/vhost.c | 78 +++++++++++++++++++++++++++++++++++--------
drivers/vhost/vhost.h | 3 +-
3 files changed, 68 insertions(+), 16 deletions(-)
@@ -1733,11 +1733,66 @@ static int log_write(void __user *log_base,returnr;}+staticintlog_write_hva(structvhost_virtqueue*vq,u64hva,u64len)+{+structvhost_umem*umem=vq->umem;+structvhost_umem_node*u;+u64gpa;+intr;+boolhit=false;++list_for_each_entry(u,&umem->umem_list,link){+if(u->userspace_addr<hva&&+u->userspace_addr+u->size>=+hva+len){+gpa=u->start+hva-u->userspace_addr;+r=log_write(vq->log_base,gpa,len);+if(r<0)+returnr;+hit=true;+}+}++/* No reverse mapping, should be a bug */+WARN_ON(!hit);+return0;+}++staticvoidlog_used(structvhost_virtqueue*vq,u64used_offset,u64len)+{+structioveciov[64];+inti,ret;++if(!vq->iotlb){+log_write(vq->log_base,vq->log_addr+used_offset,len);+return;+}++ret=translate_desc(vq,(u64)vq->used+used_offset,len,iov,64,+VHOST_ACCESS_WO);+WARN_ON(ret<0);++for(i=0;i<ret;i++){+ret=log_write_hva(vq,(u64)iov[i].iov_base,iov[i].iov_len);+WARN_ON(ret);+}+}+intvhost_log_write(structvhost_virtqueue*vq,structvhost_log*log,-unsignedintlog_num,u64len)+unsignedintlog_num,u64len,structiovec*iov,intcount){inti,r;+if(vq->iotlb){+for(i=0;i<count;i++){+r=log_write_hva(vq,(u64)iov[i].iov_base,+iov[i].iov_len);+if(r<0)+returnr;+}+return0;+}+/* Make sure data written is seen before log. */smp_wmb();for(i=0;i<log_num;++i){
@@ -1769,9 +1824,8 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)smp_wmb();/* Log used flag write. */used=&vq->used->flags;-log_write(vq->log_base,vq->log_addr+-(used-(void__user*)vq->used),-sizeofvq->used->flags);+log_used(vq,(used-(void__user*)vq->used),+sizeofvq->used->flags);if(vq->log_ctx)eventfd_signal(vq->log_ctx,1);}
@@ -2191,10 +2244,8 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,/* Make sure data is seen before log. */smp_wmb();/* Log used ring entry write. */-log_write(vq->log_base,-vq->log_addr+-((void__user*)used-(void__user*)vq->used),-count*sizeof*used);+log_used(vq,((void__user*)used-(void__user*)vq->used),+count*sizeof*used);}old=vq->last_used_idx;new=(vq->last_used_idx+=count);
@@ -2236,9 +2287,8 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,/* Make sure used idx is seen before log. */smp_wmb();/* Log used index update. */-log_write(vq->log_base,-vq->log_addr+offsetof(structvring_used,idx),-sizeofvq->used->idx);+log_used(vq,offsetof(structvring_used,idx),+sizeofvq->used->idx);if(vq->log_ctx)eventfd_signal(vq->log_ctx,1);}
From: kbuild test robot <hidden> Date: 2018-12-10 15:15:33
Hi Jason,
I love your patch! Perhaps something to improve:
[auto build test WARNING on net/master]
url: https://github.com/0day-ci/linux/commits/Jason-Wang/Fix-various-issue-of-vhost/20181210-223236
config: i386-randconfig-x072-201849 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All warnings (new ones prefixed by >>):
drivers//vhost/vhost.c: In function 'log_used':
quoted
drivers//vhost/vhost.c:1771:27: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
From: David Miller <davem@davemloft.net> Date: 2018-12-10 19:47:05
From: Jason Wang <redacted>
Date: Mon, 10 Dec 2018 17:44:50 +0800
This series tries to fix various issues of vhost:
- Patch 1 adds a missing write barrier between used idx updating and
logging.
- Patch 2-3 brings back the protection of device IOTLB through vq
mutex, this fixes possible use after free in device IOTLB entries.
- Patch 4 fixes the diry page logging when device IOTLB is
enabled. We should done through GPA instead of GIOVA, this was done
through logging through iovec and traversing GPA->HPA list for the
GPA.
Please consider them for -stable.
Looks like the kbuild robot found some problems.
->used is a pointer (which might be 32-bit) and you're casting it to
a u64 in the translate_desc() calls of patch #4.
Please make sure that you don't actually require the full domain of
a u64 in these values, as obviously if vq->used is a pointer you will
only get a 32-bit domain on 32-bit architectures.
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2018-12-11 01:30:08
On Mon, Dec 10, 2018 at 11:14:41PM +0800, kbuild test robot wrote:
Hi Jason,
I love your patch! Perhaps something to improve:
[auto build test WARNING on net/master]
url: https://github.com/0day-ci/linux/commits/Jason-Wang/Fix-various-issue-of-vhost/20181210-223236
config: i386-randconfig-x072-201849 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All warnings (new ones prefixed by >>):
drivers//vhost/vhost.c: In function 'log_used':
quoted
quoted
drivers//vhost/vhost.c:1771:27: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
ret = translate_desc(vq, (u64)vq->used + used_offset, len, iov, 64,
^
drivers//vhost/vhost.c:1776:27: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
ret = log_write_hva(vq, (u64)iov[i].iov_base, iov[i].iov_len);
^
drivers//vhost/vhost.c: In function 'vhost_log_write':
drivers//vhost/vhost.c:1788:26: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
r = log_write_hva(vq, (u64)iov[i].iov_base,
^
It's a technicality, cast to unsigned long and the warning will go away.
Donnu why does gcc bother with these warnings. Nothing is wrong
unless size of pointer is > size of int.
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2018-12-11 01:34:55
On Mon, Dec 10, 2018 at 05:44:52PM +0800, Jason Wang wrote:
quoted hunk
When we try to do rx busy polling in tx path in commit 441abde4cd84
("net: vhost: add rx busy polling in tx path"), we lock rx vq mutex
after tx vq mutex is held. This may lead deadlock so we try to lock vq
one by one in commit 78139c94dc8c ("net: vhost: lock the vqs one by
one"). With this commit, we avoid the deadlock with the assumption
that handle_rx() and handle_tx() run in a same process. But this
commit remove the protection for IOTLB updating which requires the
mutex of each vq to be held.
To solve this issue, the first step is to have a exact same lock
ordering for vhost_net. This is done through:
- For handle_rx(), if busy polling is enabled, lock tx vq immediately.
- For handle_tx(), always lock rx vq before tx vq, and unlock it if
busy polling is not enabled.
- Remove the tricky locking codes in busy polling.
With this, we can have a exact same lock ordering for vhost_net, this
allows us to safely revert commit 78139c94dc8c ("net: vhost: lock the
vqs one by one") in next patch.
The patch will add two more atomic operations on the tx path during
each round of handle_tx(). 1 byte TCP_RR does not notice such
overhead.
Fixes: commit 78139c94dc8c ("net: vhost: lock the vqs one by one")
Cc: Tonghao Zhang <redacted>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/net.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
So rx mutex taken on tx path now. And tx mutex is on rc path ... This
is just messed up. Why can't tx polling drop rx lock before
getting the tx lock and vice versa?
Or if we really wanted to force everything to be locked at
all times, let's just use a single mutex.
From: Jason Wang <hidden> Date: 2018-12-11 03:01:44
On 2018/12/11 上午3:47, David Miller wrote:
From: Jason Wang <redacted>
Date: Mon, 10 Dec 2018 17:44:50 +0800
quoted
This series tries to fix various issues of vhost:
- Patch 1 adds a missing write barrier between used idx updating and
logging.
- Patch 2-3 brings back the protection of device IOTLB through vq
mutex, this fixes possible use after free in device IOTLB entries.
- Patch 4 fixes the diry page logging when device IOTLB is
enabled. We should done through GPA instead of GIOVA, this was done
through logging through iovec and traversing GPA->HPA list for the
GPA.
Please consider them for -stable.
Looks like the kbuild robot found some problems.
->used is a pointer (which might be 32-bit) and you're casting it to
a u64 in the translate_desc() calls of patch #4.
Please make sure that you don't actually require the full domain of
a u64 in these values, as obviously if vq->used is a pointer you will
only get a 32-bit domain on 32-bit architectures.
It seems the reason is that I cast from plain void pointer directly. Let
me cast it to uintptr_t first.
Thanks
From: Jason Wang <hidden> Date: 2018-12-11 03:06:56
On 2018/12/11 上午9:34, Michael S. Tsirkin wrote:
On Mon, Dec 10, 2018 at 05:44:52PM +0800, Jason Wang wrote:
quoted
When we try to do rx busy polling in tx path in commit 441abde4cd84
("net: vhost: add rx busy polling in tx path"), we lock rx vq mutex
after tx vq mutex is held. This may lead deadlock so we try to lock vq
one by one in commit 78139c94dc8c ("net: vhost: lock the vqs one by
one"). With this commit, we avoid the deadlock with the assumption
that handle_rx() and handle_tx() run in a same process. But this
commit remove the protection for IOTLB updating which requires the
mutex of each vq to be held.
To solve this issue, the first step is to have a exact same lock
ordering for vhost_net. This is done through:
- For handle_rx(), if busy polling is enabled, lock tx vq immediately.
- For handle_tx(), always lock rx vq before tx vq, and unlock it if
busy polling is not enabled.
- Remove the tricky locking codes in busy polling.
With this, we can have a exact same lock ordering for vhost_net, this
allows us to safely revert commit 78139c94dc8c ("net: vhost: lock the
vqs one by one") in next patch.
The patch will add two more atomic operations on the tx path during
each round of handle_tx(). 1 byte TCP_RR does not notice such
overhead.
Fixes: commit 78139c94dc8c ("net: vhost: lock the vqs one by one")
Cc: Tonghao Zhang<redacted>
Signed-off-by: Jason Wang<redacted>
---
drivers/vhost/net.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
So rx mutex taken on tx path now. And tx mutex is on rc path ... This
is just messed up. Why can't tx polling drop rx lock before
getting the tx lock and vice versa?
Because we want to poll both tx and rx virtqueue at the same time
(vhost_net_busy_poll()).
while (vhost_can_busy_poll(endtime)) {
if (vhost_has_work(&net->dev)) {
*busyloop_intr = true;
break;
}
if ((sock_has_rx_data(sock) &&
!vhost_vq_avail_empty(&net->dev, rvq)) ||
!vhost_vq_avail_empty(&net->dev, tvq))
break;
cpu_relax();
}
And we disable kicks and notification for better performance.
Or if we really wanted to force everything to be locked at
all times, let's just use a single mutex.
We could, but it might requires more changes which could be done for
-next I believe.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2018-12-11 04:04:11
On Tue, Dec 11, 2018 at 11:06:43AM +0800, Jason Wang wrote:
On 2018/12/11 上午9:34, Michael S. Tsirkin wrote:
quoted
On Mon, Dec 10, 2018 at 05:44:52PM +0800, Jason Wang wrote:
quoted
When we try to do rx busy polling in tx path in commit 441abde4cd84
("net: vhost: add rx busy polling in tx path"), we lock rx vq mutex
after tx vq mutex is held. This may lead deadlock so we try to lock vq
one by one in commit 78139c94dc8c ("net: vhost: lock the vqs one by
one"). With this commit, we avoid the deadlock with the assumption
that handle_rx() and handle_tx() run in a same process. But this
commit remove the protection for IOTLB updating which requires the
mutex of each vq to be held.
To solve this issue, the first step is to have a exact same lock
ordering for vhost_net. This is done through:
- For handle_rx(), if busy polling is enabled, lock tx vq immediately.
- For handle_tx(), always lock rx vq before tx vq, and unlock it if
busy polling is not enabled.
- Remove the tricky locking codes in busy polling.
With this, we can have a exact same lock ordering for vhost_net, this
allows us to safely revert commit 78139c94dc8c ("net: vhost: lock the
vqs one by one") in next patch.
The patch will add two more atomic operations on the tx path during
each round of handle_tx(). 1 byte TCP_RR does not notice such
overhead.
Fixes: commit 78139c94dc8c ("net: vhost: lock the vqs one by one")
Cc: Tonghao Zhang<redacted>
Signed-off-by: Jason Wang<redacted>
---
drivers/vhost/net.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
So rx mutex taken on tx path now. And tx mutex is on rc path ... This
is just messed up. Why can't tx polling drop rx lock before
getting the tx lock and vice versa?
Because we want to poll both tx and rx virtqueue at the same time
(vhost_net_busy_poll()).
while (vhost_can_busy_poll(endtime)) {
if (vhost_has_work(&net->dev)) {
*busyloop_intr = true;
break;
}
if ((sock_has_rx_data(sock) &&
!vhost_vq_avail_empty(&net->dev, rvq)) ||
!vhost_vq_avail_empty(&net->dev, tvq))
break;
cpu_relax();
}
And we disable kicks and notification for better performance.
Right but it's all slow path - it happens when queue is
otherwise empty. So this is what I am saying: let's drop the locks
we hold around this.
quoted
Or if we really wanted to force everything to be locked at
all times, let's just use a single mutex.
We could, but it might requires more changes which could be done for -next I
believe.
Thanks
I'd rather we kept the fine grained locking. E.g. people are
looking at splitting the tx and rx threads. But if not possible
let's fix it cleanly with a coarse-grained one. A mess here will
just create more trouble later.
--
MST
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Jason Wang <hidden> Date: 2018-12-12 03:04:07
On 2018/12/11 下午12:04, Michael S. Tsirkin wrote:
On Tue, Dec 11, 2018 at 11:06:43AM +0800, Jason Wang wrote:
quoted
On 2018/12/11 上午9:34, Michael S. Tsirkin wrote:
quoted
On Mon, Dec 10, 2018 at 05:44:52PM +0800, Jason Wang wrote:
quoted
When we try to do rx busy polling in tx path in commit 441abde4cd84
("net: vhost: add rx busy polling in tx path"), we lock rx vq mutex
after tx vq mutex is held. This may lead deadlock so we try to lock vq
one by one in commit 78139c94dc8c ("net: vhost: lock the vqs one by
one"). With this commit, we avoid the deadlock with the assumption
that handle_rx() and handle_tx() run in a same process. But this
commit remove the protection for IOTLB updating which requires the
mutex of each vq to be held.
To solve this issue, the first step is to have a exact same lock
ordering for vhost_net. This is done through:
- For handle_rx(), if busy polling is enabled, lock tx vq immediately.
- For handle_tx(), always lock rx vq before tx vq, and unlock it if
busy polling is not enabled.
- Remove the tricky locking codes in busy polling.
With this, we can have a exact same lock ordering for vhost_net, this
allows us to safely revert commit 78139c94dc8c ("net: vhost: lock the
vqs one by one") in next patch.
The patch will add two more atomic operations on the tx path during
each round of handle_tx(). 1 byte TCP_RR does not notice such
overhead.
Fixes: commit 78139c94dc8c ("net: vhost: lock the vqs one by one")
Cc: Tonghao Zhang<redacted>
Signed-off-by: Jason Wang<redacted>
---
drivers/vhost/net.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
So rx mutex taken on tx path now. And tx mutex is on rc path ... This
is just messed up. Why can't tx polling drop rx lock before
getting the tx lock and vice versa?
Because we want to poll both tx and rx virtqueue at the same time
(vhost_net_busy_poll()).
while (vhost_can_busy_poll(endtime)) {
if (vhost_has_work(&net->dev)) {
*busyloop_intr = true;
break;
}
if ((sock_has_rx_data(sock) &&
!vhost_vq_avail_empty(&net->dev, rvq)) ||
!vhost_vq_avail_empty(&net->dev, tvq))
break;
cpu_relax();
}
And we disable kicks and notification for better performance.
Right but it's all slow path - it happens when queue is
otherwise empty. So this is what I am saying: let's drop the locks
we hold around this.
Is this really safe? I looks to me it can race with SET_VRING_ADDR. And
the codes did more:
- access sock object
- access device IOTLB
- enable and disable notification
None of above is safe without the protection of vq mutex.
quoted
quoted
Or if we really wanted to force everything to be locked at
all times, let's just use a single mutex.
We could, but it might requires more changes which could be done for -next I
believe.
Thanks
I'd rather we kept the fine grained locking. E.g. people are
looking at splitting the tx and rx threads. But if not possible
let's fix it cleanly with a coarse-grained one. A mess here will
just create more trouble later.
I believe we won't go back to coarse one. Looks like we can solve this
by using mutex_trylock() for rxq during TX. And don't do polling for rxq
is a IOTLB updating is pending.
Let me post V2.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2018-12-12 03:40:49
On Wed, Dec 12, 2018 at 11:03:57AM +0800, Jason Wang wrote:
On 2018/12/11 下午12:04, Michael S. Tsirkin wrote:
quoted
On Tue, Dec 11, 2018 at 11:06:43AM +0800, Jason Wang wrote:
quoted
On 2018/12/11 上午9:34, Michael S. Tsirkin wrote:
quoted
On Mon, Dec 10, 2018 at 05:44:52PM +0800, Jason Wang wrote:
quoted
When we try to do rx busy polling in tx path in commit 441abde4cd84
("net: vhost: add rx busy polling in tx path"), we lock rx vq mutex
after tx vq mutex is held. This may lead deadlock so we try to lock vq
one by one in commit 78139c94dc8c ("net: vhost: lock the vqs one by
one"). With this commit, we avoid the deadlock with the assumption
that handle_rx() and handle_tx() run in a same process. But this
commit remove the protection for IOTLB updating which requires the
mutex of each vq to be held.
To solve this issue, the first step is to have a exact same lock
ordering for vhost_net. This is done through:
- For handle_rx(), if busy polling is enabled, lock tx vq immediately.
- For handle_tx(), always lock rx vq before tx vq, and unlock it if
busy polling is not enabled.
- Remove the tricky locking codes in busy polling.
With this, we can have a exact same lock ordering for vhost_net, this
allows us to safely revert commit 78139c94dc8c ("net: vhost: lock the
vqs one by one") in next patch.
The patch will add two more atomic operations on the tx path during
each round of handle_tx(). 1 byte TCP_RR does not notice such
overhead.
Fixes: commit 78139c94dc8c ("net: vhost: lock the vqs one by one")
Cc: Tonghao Zhang<redacted>
Signed-off-by: Jason Wang<redacted>
---
drivers/vhost/net.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
So rx mutex taken on tx path now. And tx mutex is on rc path ... This
is just messed up. Why can't tx polling drop rx lock before
getting the tx lock and vice versa?
Because we want to poll both tx and rx virtqueue at the same time
(vhost_net_busy_poll()).
while (vhost_can_busy_poll(endtime)) {
if (vhost_has_work(&net->dev)) {
*busyloop_intr = true;
break;
}
if ((sock_has_rx_data(sock) &&
!vhost_vq_avail_empty(&net->dev, rvq)) ||
!vhost_vq_avail_empty(&net->dev, tvq))
break;
cpu_relax();
}
And we disable kicks and notification for better performance.
Right but it's all slow path - it happens when queue is
otherwise empty. So this is what I am saying: let's drop the locks
we hold around this.
Is this really safe? I looks to me it can race with SET_VRING_ADDR. And the
codes did more:
- access sock object
- access device IOTLB
- enable and disable notification
None of above is safe without the protection of vq mutex.
ys but take another lock. just not nested.
quoted
quoted
quoted
Or if we really wanted to force everything to be locked at
all times, let's just use a single mutex.
We could, but it might requires more changes which could be done for -next I
believe.
Thanks
I'd rather we kept the fine grained locking. E.g. people are
looking at splitting the tx and rx threads. But if not possible
let's fix it cleanly with a coarse-grained one. A mess here will
just create more trouble later.
I believe we won't go back to coarse one. Looks like we can solve this by
using mutex_trylock() for rxq during TX. And don't do polling for rxq is a
IOTLB updating is pending.
Let me post V2.
Thanks
From: kbuild test robot <hidden> Date: 2018-12-19 17:31:10
Hi Jason,
I love your patch! Perhaps something to improve:
[auto build test WARNING on net/master]
url: https://github.com/0day-ci/linux/commits/Jason-Wang/Fix-various-issue-of-vhost/20181210-223236
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All warnings (new ones prefixed by >>):
include/linux/slab.h:332:43: warning: dubious: x & !y
include/linux/slab.h:332:43: warning: dubious: x & !y
include/linux/slab.h:332:43: warning: dubious: x & !y
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
include/linux/slab.h:332:43: warning: dubious: x & !y
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
quoted
drivers/vhost/vhost.c:1771:35: warning: cast removes address space '<asn:1>' of expression
drivers/vhost/vhost.c:1776:42: warning: cast removes address space '<asn:1>' of expression
drivers/vhost/vhost.c:1788:48: warning: cast removes address space '<asn:1>' of expression
drivers/vhost/vhost.c:1819:13: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:1819:13: expected void *addr
drivers/vhost/vhost.c:1819:13: got restricted __virtio16 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:1837:13: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:1837:13: expected void *addr
drivers/vhost/vhost.c:1837:13: got restricted __virtio16 [noderef] [usertype] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:1874:13: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:1874:13: expected void *addr
drivers/vhost/vhost.c:1874:13: got restricted __virtio16 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2073:21: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2073:21: expected void *addr
drivers/vhost/vhost.c:2073:21: got restricted __virtio16 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2100:13: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2100:13: expected void *addr
drivers/vhost/vhost.c:2100:13: got restricted __virtio16 [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2231:21: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2231:21: expected void *addr
drivers/vhost/vhost.c:2231:21: got restricted __virtio32 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2235:21: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2235:21: expected void *addr
drivers/vhost/vhost.c:2235:21: got restricted __virtio32 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2281:13: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2281:13: expected void *addr
drivers/vhost/vhost.c:2281:13: got restricted __virtio16 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2315:21: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2315:21: expected void *addr
drivers/vhost/vhost.c:2315:21: got restricted __virtio16 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2329:13: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2329:13: expected void *addr
drivers/vhost/vhost.c:2329:13: got restricted __virtio16 [noderef] [usertype] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
drivers/vhost/vhost.c:851:42: got void *addr
drivers/vhost/vhost.c:2374:13: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:2374:13: expected void *addr
drivers/vhost/vhost.c:2374:13: got restricted __virtio16 [noderef] <asn:1> *<noident>
drivers/vhost/vhost.c:704:17: warning: incorrect type in return expression (different address spaces)
drivers/vhost/vhost.c:704:17: expected void [noderef] <asn:1> *
drivers/vhost/vhost.c:704:17: got void *<noident>
drivers/vhost/vhost.c:851:42: warning: incorrect type in argument 2 (different address spaces)
drivers/vhost/vhost.c:851:42: expected void [noderef] <asn:1> *addr
vim +1771 drivers/vhost/vhost.c
1760
1761 static void log_used(struct vhost_virtqueue *vq, u64 used_offset, u64 len)
1762 {
1763 struct iovec iov[64];
1764 int i, ret;
1765
1766 if (!vq->iotlb) {
1767 log_write(vq->log_base, vq->log_addr + used_offset, len);
1768 return;
1769 }
1770
1771 ret = translate_desc(vq, (u64)vq->used + used_offset, len, iov, 64,
1772 VHOST_ACCESS_WO);
1773 WARN_ON(ret < 0);
1774
1775 for (i = 0; i < ret; i++) {
1776 ret = log_write_hva(vq, (u64)iov[i].iov_base, iov[i].iov_len);
1777 WARN_ON(ret);
1778 }
1779 }
1780
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation