[dpdk-dev,v2] vhost: flush used->idx update before reading avail->flags

Message ID 1430305884-9139-1-git-send-email-huawei.xie@intel.com (mailing list archive)
State Accepted, archived
Headers

Commit Message

Huawei Xie April 29, 2015, 11:11 a.m. UTC
  update of used->idx and read of avail->flags could be reordered.
memory fence should be used to ensure the order, otherwise guest could see a stale used->idx value after it toggles the interrupt suppression flag.
After guest sets the interrupt suppression flag, it will check if there is more buffer to process through used->idx. If it sees a stale value, it will exit the processing while host willn't send interrupt to guest.

Signed-off-by: Huawei Xie <huawei.xie@intel.com>
---
 lib/librte_vhost/vhost_rxtx.c | 6 ++++++
 1 file changed, 6 insertions(+)
  

Comments

Thomas Monjalon May 13, 2015, 10:46 a.m. UTC | #1
2015-04-29 19:11, Huawei Xie:
> update of used->idx and read of avail->flags could be reordered.
> memory fence should be used to ensure the order, otherwise guest could see a stale used->idx value after it toggles the interrupt suppression flag.
> After guest sets the interrupt suppression flag, it will check if there is more buffer to process through used->idx. If it sees a stale value, it will exit the processing while host willn't send interrupt to guest.
> 
> Signed-off-by: Huawei Xie <huawei.xie@intel.com>

Applied with following title, thanks
	vhost: fix virtio freeze due to missed interrupt
  
Nikita Kalyazin May 15, 2015, 1:43 p.m. UTC | #2
Hi,


Maybe I missed a part of the discussion, but is there any special purpose for using rte_mb (both read and write fence) here rather than rte_wmb (write fence only)?
  
Michael S. Tsirkin May 15, 2015, 3:23 p.m. UTC | #3
On Fri, May 15, 2015 at 04:43:33PM +0300, Nikita Kalyazin wrote:
> Hi,
> 
> 
> Maybe I missed a part of the discussion, but is there any special purpose for using rte_mb (both read and write fence) here rather than rte_wmb (write fence only)?

The fence is between write of used->idx and read of avail->flags, so
rte_wmb won't do anything useful.

> -- 
> 
> Best regards,
> 
> Nikita Kalyazin,
> n.kalyazin@samsung.com
> 
> Software Engineer
> CE OS Group
> Samsung R&D Institute Russia
> Tel: +7 (495) 797-25-00 #3816
> Tel: +7 (495) 797-25-03
> Office #1501, 12-1, Dvintsev str.,
> Moscow, 127018, Russia
> 
> On Wed, May 13, 2015 at 12:46:30PM +0200, Thomas Monjalon wrote:
> > 2015-04-29 19:11, Huawei Xie:
> > > update of used->idx and read of avail->flags could be reordered.
> > > memory fence should be used to ensure the order, otherwise guest could see a stale used->idx value after it toggles the interrupt suppression flag.
> > > After guest sets the interrupt suppression flag, it will check if there is more buffer to process through used->idx. If it sees a stale value, it will exit the processing while host willn't send interrupt to guest.
> > > 
> > > Signed-off-by: Huawei Xie <huawei.xie@intel.com>
> > 
> > Applied with following title, thanks
> > 	vhost: fix virtio freeze due to missed interrupt
> >
  
Nikita Kalyazin May 18, 2015, 6:18 a.m. UTC | #4
Ah, sorry. I looked at it without the context. Thanks.
  

Patch

diff --git a/lib/librte_vhost/vhost_rxtx.c b/lib/librte_vhost/vhost_rxtx.c
index 510ffe8..4809d32 100644
--- a/lib/librte_vhost/vhost_rxtx.c
+++ b/lib/librte_vhost/vhost_rxtx.c
@@ -178,6 +178,9 @@  virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id,
 	*(volatile uint16_t *)&vq->used->idx += count;
 	vq->last_used_idx = res_end_idx;
 
+	/* flush used->idx update before we read avail->flags. */
+	rte_mb();
+
 	/* Kick the guest if necessary. */
 	if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
 		eventfd_write((int)vq->callfd, 1);
@@ -505,6 +508,9 @@  virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,
 		*(volatile uint16_t *)&vq->used->idx += entry_success;
 		vq->last_used_idx = res_end_idx;
 
+		/* flush used->idx update before we read avail->flags. */
+		rte_mb();
+
 		/* Kick the guest if necessary. */
 		if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
 			eventfd_write((int)vq->callfd, 1);