From 9858d374ad1f789c8c860e00e2b8d4d01fdc1e73 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 20 Dec 2018 10:44:47 +0100 Subject: virtio: fix kick race issue [VPP-1489] Change-Id: I25b2a28513821bc5eab9ac6890a3964d412b0399 Signed-off-by: Damjan Marion (cherry picked from commit e40231b1ecf4b49faaa9ce7b615a7d867104825b) --- src/vnet/devices/virtio/device.c | 10 +++++----- src/vnet/devices/virtio/node.c | 18 +++++++++++++----- src/vnet/devices/virtio/virtio.h | 11 +++++++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/vnet/devices/virtio/device.c b/src/vnet/devices/virtio/device.c index c7efe6519cd..d50ef88d3fb 100644 --- a/src/vnet/devices/virtio/device.c +++ b/src/vnet/devices/virtio/device.c @@ -169,7 +169,6 @@ add_buffer_to_slot (vlib_main_t * vm, virtio_vring_t * vring, u32 bi, return n_added; } - static_always_inline uword virtio_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, virtio_if_t * vif) @@ -184,6 +183,10 @@ virtio_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node, clib_spinlock_lock_if_init (&vif->lockp); + if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0 && + vring->last_kick_avail_idx != vring->avail->idx) + virtio_kick (vring); + /* free consumed buffers */ virtio_free_used_desc (vm, vring); @@ -209,10 +212,7 @@ virtio_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vring->desc_next = next; vring->desc_in_use = used; if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0) - { - u64 x = 1; - CLIB_UNUSED (int r) = write (vring->kick_fd, &x, sizeof (x)); - } + virtio_kick (vring); } diff --git a/src/vnet/devices/virtio/node.c b/src/vnet/devices/virtio/node.c index 339c48c93f5..419b025b3ae 100644 --- a/src/vnet/devices/virtio/node.c +++ b/src/vnet/devices/virtio/node.c @@ -87,17 +87,23 @@ virtio_refill_vring (vlib_main_t * vm, virtio_vring_t * vring) u16 sz = vring->size; u16 mask = sz - 1; +more: used = vring->desc_in_use; if (sz - used < sz / 8) return; - n_slots = sz - used; + /* deliver free buffers in chunks of 64 */ + n_slots = clib_min (sz - used, 64); + next = vring->desc_next; avail = vring->avail->idx; n_slots = vlib_buffer_alloc_to_ring (vm, vring->buffers, next, vring->size, n_slots); + if (n_slots == 0) + return; + while (n_slots) { struct vring_desc *d = &vring->desc[next];; @@ -117,10 +123,8 @@ virtio_refill_vring (vlib_main_t * vm, virtio_vring_t * vring) vring->desc_in_use = used; if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0) - { - u64 b = 1; - CLIB_UNUSED (int r) = write (vring->kick_fd, &b, sizeof (b)); - } + virtio_kick (vring); + goto more; } static_always_inline uword @@ -140,6 +144,10 @@ virtio_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, u16 last = vring->last_used_idx; u16 n_left = vring->used->idx - last; + if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0 && + vring->last_kick_avail_idx != vring->avail->idx) + virtio_kick (vring); + if (n_left == 0) goto refill; diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h index 5fc521672d9..8ac87c8ccfd 100644 --- a/src/vnet/devices/virtio/virtio.h +++ b/src/vnet/devices/virtio/virtio.h @@ -86,6 +86,7 @@ typedef struct u32 call_file_index; u32 *buffers; u16 last_used_idx; + u16 last_kick_avail_idx; } virtio_vring_t; typedef struct @@ -136,6 +137,16 @@ extern void virtio_free_used_desc (vlib_main_t * vm, virtio_vring_t * vring); format_function_t format_virtio_device_name; +static_always_inline void +virtio_kick (virtio_vring_t * vring) +{ + u64 x = 1; + int __clib_unused r; + + r = write (vring->kick_fd, &x, sizeof (x)); + vring->last_kick_avail_idx = vring->avail->idx; +} + #endif /* _VNET_DEVICES_VIRTIO_VIRTIO_H_ */ /* -- cgit 1.2.3-korg