diff mbox

[2/2] rtl8139: flush queued packets when RxBufPtr is written

Message ID 1369406295-20411-3-git-send-email-stefanha@redhat.com
State New
Headers show

Commit Message

Stefan Hajnoczi May 24, 2013, 2:38 p.m. UTC
Net queues support efficient "receive disable".  For example, tap's file
descriptor will not be polled while its peer has receive disabled.  This
saves CPU cycles for needlessly copying and then dropping packets which
the peer cannot receive.

rtl8139 is missing the qemu_flush_queued_packets() call that wakes the
queue up when receive becomes possible again.

As a result, the Windows 7 guest driver reaches a state where the
rtl8139 cannot receive packets.  The driver has actually refilled the
receive buffer but we never resume reception.

The bug can be reproduced by running a large FTP 'get' inside a Windows
7 guest:

  $ qemu -netdev tap,id=tap0,...
         -device rtl8139,netdev=tap0

The Linux guest driver does not trigger the bug, probably due to a
different buffer management strategy.

Reported-by: Oliver Francke <oliver.francke@filoo.de>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/net/rtl8139.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Paolo Bonzini May 24, 2013, 3:18 p.m. UTC | #1
Il 24/05/2013 16:38, Stefan Hajnoczi ha scritto:
> Net queues support efficient "receive disable".  For example, tap's file
> descriptor will not be polled while its peer has receive disabled.  This
> saves CPU cycles for needlessly copying and then dropping packets which
> the peer cannot receive.
> 
> rtl8139 is missing the qemu_flush_queued_packets() call that wakes the
> queue up when receive becomes possible again.
> 
> As a result, the Windows 7 guest driver reaches a state where the
> rtl8139 cannot receive packets.  The driver has actually refilled the
> receive buffer but we never resume reception.
> 
> The bug can be reproduced by running a large FTP 'get' inside a Windows
> 7 guest:
> 
>   $ qemu -netdev tap,id=tap0,...
>          -device rtl8139,netdev=tap0
> 
> The Linux guest driver does not trigger the bug, probably due to a
> different buffer management strategy.
> 
> Reported-by: Oliver Francke <oliver.francke@filoo.de>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  hw/net/rtl8139.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
> index 9369507..7993f9f 100644
> --- a/hw/net/rtl8139.c
> +++ b/hw/net/rtl8139.c
> @@ -2575,6 +2575,9 @@ static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
>      /* this value is off by 16 */
>      s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
>  
> +    /* more buffer space may be available so try to receive */
> +    qemu_flush_queued_packets(qemu_get_queue(s->nic));
> +
>      DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
>          s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
>  }
> 

Do you have time to update the branch with a "Cc: qemu-stable@nongnu.org"?

Paolo
Stefan Hajnoczi May 27, 2013, 9 a.m. UTC | #2
On Fri, May 24, 2013 at 05:18:09PM +0200, Paolo Bonzini wrote:
> Il 24/05/2013 16:38, Stefan Hajnoczi ha scritto:
> > diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
> > index 9369507..7993f9f 100644
> > --- a/hw/net/rtl8139.c
> > +++ b/hw/net/rtl8139.c
> > @@ -2575,6 +2575,9 @@ static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
> >      /* this value is off by 16 */
> >      s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
> >  
> > +    /* more buffer space may be available so try to receive */
> > +    qemu_flush_queued_packets(qemu_get_queue(s->nic));
> > +
> >      DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
> >          s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
> >  }
> > 
> 
> Do you have time to update the branch with a "Cc: qemu-stable@nongnu.org"?

It has been merged.  Will try to CC qemu-stable in the future.

Stefan
diff mbox

Patch

diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 9369507..7993f9f 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -2575,6 +2575,9 @@  static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
     /* this value is off by 16 */
     s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
 
+    /* more buffer space may be available so try to receive */
+    qemu_flush_queued_packets(qemu_get_queue(s->nic));
+
     DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
         s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
 }