Browse Source

virtio-net: Fix kick/wait logic

The virtnet_transmit() logic for waiting the packet to be transmitted is
reversed: we can't wait the packet to be transmitted if we didn't kick()
the ring yet. The vring_more_used() while loop logic is reversed also,
that explains why the code works today.

The current code risks trying to free a buffer from the used ring
when none was available, that will happen most times because KVM
doesn't handle the packet immediately on kick(). Luckily it was working
because it was unlikely to have a buffer still queued for transmit when
virtnet_transmit() was called.

Also, adds a BUG_ON() to vring_get_buf(), to catch cases where we try
to free a buffer from the used ring when there was none available.

Patch for Etherboot. gPXE has the same problem on the code, but I hadn't
a chance to test gPXE using virtio-net yet.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
tags/v0.9.6
Eduardo Habkost 15 years ago
parent
commit
744b98d273
1 changed files with 5 additions and 3 deletions
  1. 5
    3
      src/drivers/net/virtio-net.c

+ 5
- 3
src/drivers/net/virtio-net.c View File

@@ -187,6 +187,8 @@ static int vring_get_buf(int queue_index, unsigned int *len)
187 187
    u32 id;
188 188
    int ret;
189 189
 
190
+   BUG_ON(!vring_more_used(queue_index));
191
+
190 192
    elem = &vr->used->ring[last_used_idx[queue_index] % vr->num];
191 193
    wmb();
192 194
    id = elem->id;
@@ -365,6 +367,8 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
365 367
 
366 368
    vring_add_buf(TX_INDEX, 0, 0);
367 369
 
370
+   vring_kick(nic, TX_INDEX, 1);
371
+
368 372
    /*
369 373
     * http://www.etherboot.org/wiki/dev/devmanual
370 374
     *
@@ -372,13 +376,11 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
372 376
     *    before returning from this routine"
373 377
     */
374 378
 
375
-   while (vring_more_used(TX_INDEX)) {
379
+   while (!vring_more_used(TX_INDEX)) {
376 380
            mb();
377 381
            udelay(10);
378 382
    }
379 383
 
380
-   vring_kick(nic, TX_INDEX, 1);
381
-
382 384
    /* free desc */
383 385
 
384 386
    (void)vring_get_buf(TX_INDEX, NULL);

Loading…
Cancel
Save