virtio_ring: don't update event idx on get_buf
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@bytedance.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Message-Id: <20230329102300.61000-1-huangjie.albert@bytedance.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
4bb94d2de2
commit
6c0b057cec
@ -854,6 +854,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;
|
||||
@ -1699,6 +1707,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);
|
||||
}
|
||||
@ -2330,12 +2346,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
|
||||
|
Loading…
x
Reference in New Issue
Block a user