virtio: fix kick race issue 56/16556/4
authorDamjan Marion <damarion@cisco.com>
Thu, 20 Dec 2018 09:44:47 +0000 (10:44 +0100)
committerDamjan Marion <dmarion@me.com>
Tue, 8 Jan 2019 17:03:56 +0000 (17:03 +0000)
Change-Id: I25b2a28513821bc5eab9ac6890a3964d412b0399
Signed-off-by: Damjan Marion <damarion@cisco.com>
src/vnet/devices/virtio/device.c
src/vnet/devices/virtio/node.c
src/vnet/devices/virtio/virtio.h

index 2b2c853..7c66a60 100644 (file)
@@ -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);
     }
 
 
index e019513..d7a0b39 100644 (file)
@@ -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;
 
index e401f2d..841441b 100644 (file)
@@ -87,6 +87,7 @@ typedef struct
   u32 call_file_index;
   u32 *buffers;
   u16 last_used_idx;
+  u16 last_kick_avail_idx;
 } virtio_vring_t;
 
 typedef struct
@@ -137,6 +138,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_ */
 
 /*