Patch "virtio_ring: don't update event idx on get_buf" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    virtio_ring: don't update event idx on get_buf

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     virtio_ring-don-t-update-event-idx-on-get_buf.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 8be5cb575b8f35fc371ba5e2c6a7b82f298a49d9
Author: Albert Huang <huangjie.albert@xxxxxxxxxxxxx>
Date:   Wed Mar 29 18:23:00 2023 +0800

    virtio_ring: don't update event idx on get_buf
    
    [ Upstream commit 6c0b057cec5eade4c3afec3908821176931a9997 ]
    
    In virtio_net, if we disable napi_tx, when we trigger a tx interrupt,
    the vq->event_triggered will be set to true. It is then never reset
    until we explicitly call virtqueue_enable_cb_delayed or
    virtqueue_enable_cb_prepare.
    
    If we disable the napi_tx, virtqueue_enable_cb* will only be called when
    the tx ring is getting relatively empty.
    
    Since event_triggered is true, VRING_AVAIL_F_NO_INTERRUPT or
    VRING_PACKED_EVENT_FLAG_DISABLE will not be set. As a result we update
    vring_used_event(&vq->split.vring) or vq->packed.vring.driver->off_wrap
    every time we call virtqueue_get_buf_ctx. This causes more interrupts.
    
    To summarize:
    1) event_triggered was set to true in vring_interrupt()
    2) after this nothing will happen in virtqueue_disable_cb() so
       VRING_AVAIL_F_NO_INTERRUPT is not set in avail_flags_shadow
    3) virtqueue_get_buf_ctx_split() will still think the cb is enabled
       and then it will publish a new event index
    
    To fix:
    update VRING_AVAIL_F_NO_INTERRUPT or VRING_PACKED_EVENT_FLAG_DISABLE in
    the vq when we call virtqueue_disable_cb even when event_triggered is
    true.
    
    Tested with iperf:
    iperf3 tcp stream:
    vm1 -----------------> vm2
    vm2 just receives tcp data stream from vm1, and sends acks to vm1,
    there are many tx interrupts in vm2.
    with the patch applied there are just a few tx interrupts.
    
    v2->v3:
    -update the interrupt disable flag even with the event_triggered is set,
    -instead of checking whether event_triggered is set in
    -virtqueue_get_buf_ctx_{packed/split}, will cause the drivers  which have
    -not called virtqueue_{enable/disable}_cb to miss notifications.
    
    v3->v4:
    -remove change for
    -"if (vq->packed.event_flags_shadow != VRING_PACKED_EVENT_FLAG_DISABLE)"
    -in virtqueue_disable_cb_packed
    
    Fixes: 8d622d21d248 ("virtio: fix up virtio_disable_cb")
    Signed-off-by: Albert Huang <huangjie.albert@xxxxxxxxxxxxx>
    Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx>
    Signed-off-by: Jason Wang <jasowang@xxxxxxxxxx>
    Message-Id: <20230329102300.61000-1-huangjie.albert@xxxxxxxxxxxxx>
    Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 603a6f4345efd..800df63c58692 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -809,6 +809,14 @@ static void virtqueue_disable_cb_split(struct virtqueue *_vq)
 
 	if (!(vq->split.avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
 		vq->split.avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
+
+		/*
+		 * If device triggered an event already it won't trigger one again:
+		 * no need to disable.
+		 */
+		if (vq->event_triggered)
+			return;
+
 		if (vq->event)
 			/* TODO: this is a hack. Figure out a cleaner value to write. */
 			vring_used_event(&vq->split.vring) = 0x0;
@@ -1500,6 +1508,14 @@ static void virtqueue_disable_cb_packed(struct virtqueue *_vq)
 
 	if (vq->packed.event_flags_shadow != VRING_PACKED_EVENT_FLAG_DISABLE) {
 		vq->packed.event_flags_shadow = VRING_PACKED_EVENT_FLAG_DISABLE;
+
+		/*
+		 * If device triggered an event already it won't trigger one again:
+		 * no need to disable.
+		 */
+		if (vq->event_triggered)
+			return;
+
 		vq->packed.vring.driver->flags =
 			cpu_to_le16(vq->packed.event_flags_shadow);
 	}
@@ -2019,12 +2035,6 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
 {
 	struct vring_virtqueue *vq = to_vvq(_vq);
 
-	/* If device triggered an event already it won't trigger one again:
-	 * no need to disable.
-	 */
-	if (vq->event_triggered)
-		return;
-
 	if (vq->packed_ring)
 		virtqueue_disable_cb_packed(_vq);
 	else



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux