Date: Thu, 21 Oct 2004 17:41:50 GMT From: James Van Bokkelen <jbvb@sandstorm.net> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/72970: em driver can hang when mbuf starvation occurs Message-ID: <200410211741.i9LHfoYa022424@www.freebsd.org> Resent-Message-ID: <200410211750.i9LHoKkx077444@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 72970
>Category: kern
>Synopsis: em driver can hang when mbuf starvation occurs
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Thu Oct 21 17:50:20 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator: James Van Bokkelen
>Release: 4.8
>Organization:
Sandstorm Enterprises Inc.
>Environment:
FreeBSD ni8 4.8-RELEASE FreeBSD 4.8-RELEASE #0: Fri Oct 15 15:02:46 EDT 2004 prod@sandstorm.net:/usr/src/sys/compile/NI_3X_FREEBSD48_DUAL i386
>Description:
In file sys/dev/em/if_em.c, in function process_receive_interrupts(),
(at line 2469 in v1.2.2.16, still present in 1.50 viewed via CVS
on 21-Oct-2004), there is a call to em_get_buf(). If this fails due
to mbuf starvation, the driver presently counts the error, frees any
chain being built, puts the old buffer back in the receive and breaks
out of the while(current_desc->status...) loop. This results in the
interrupt being dismissed without updating the receive queue tail
pointer, and the card never interrupts again.
>How-To-Repeat:
Stress a FreeBSD system with an em interface by receiving a large
amount of traffic in promiscuous mode from several different senders
while simultaneously writing large amounts of data to the disk.
Observe that the em interface stops receiving new packets, and starts
rapidly counting missed packets. Condition can be cleared by
ifconfig em0 down && ifconfig em0 up
or
ifconfig em0 media auto
>Fix:
I replaced the offending block of code with a goto:
if (accept_frame) {
if (em_get_buf(i, adapter, NULL) == ENOBUFS) {
goto next_rx_pkt; /* treat starvation like a runt or overrun */
This is aimed at a new label in the 'else' clause of the enclosing
'if (accept_frame)':
} else {
next_rx_pkt: /* Come here when starvation forces us to re-use an mbuf cluster */
adapter->dropped_pkts++;
em_get_buf(i, adapter, mp);
if (adapter->fmp != NULL)
m_freem(adapter->fmp);
adapter->fmp = NULL;
adapter->lmp = NULL;
}
/* Zero out the receive descriptors status */
This keeps the driver from prematurely dismissing the interrupt and
going deaf to incoming packets.
>Release-Note:
>Audit-Trail:
>Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200410211741.i9LHfoYa022424>
