Date: Fri, 31 Dec 2004 00:43:24 +0100 (CET) From: Antoine Brodin <antoine.brodin@laposte.net> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/75677: [patch] sk(4): plug leaks and fix acquiring duplicate lock of same type: "network driver" Message-ID: <200412302343.iBUNhOAD001307@barton.dreadbsd.org> Resent-Message-ID: <200412302350.iBUNo6bx033041@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 75677
>Category: kern
>Synopsis: [patch] sk(4): plug leaks and fix acquiring duplicate lock of same type: "network driver"
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Thu Dec 30 23:50:06 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator: Antoine Brodin
>Release: FreeBSD 6.0-CURRENT i386
>Organization:
none
>Environment:
System: FreeBSD barton.dreadbsd.org 6.0-CURRENT FreeBSD 6.0-CURRENT #1: Thu Dec 30 19:02:55 CET 2004 antoine@barton.dreadbsd.org:/usr/obj/usr/src/sys/BARTON i386
>Description:
* Witness reports this on a -current box :
acquiring duplicate lock of same type: "network driver"
1st nv0 @ /usr/ports/net/nvnet/work/nvnet/module/../src/if_nv.c:1511
2nd skc0 @ /usr/src/sys/modules/sk/../../pci/if_sk.c:1112
KDB: stack backtrace:
witness_checkorder(c2855c44,9,c07316ba,458) at witness_checkorder+0x500
_mtx_lock_flags(c2855c44,0,c07316ba,458,c2ac4e00) at _mtx_lock_flags+0x40
sk_jfree(e5a44340,c28e3000,0,c2857c00,e3c79c80) at sk_jfree+0x33
mb_free_ext(c2ac4e00) at mb_free_ext+0x36
m_freem(c2ac4e00,c2857c00,e5901000,e56fb0e0,c2857e60) at m_freem+0x21
nv_ospackettx(c2857c00,e56fb0e0,1,e5901000,0) at nv_ospackettx+0x73
UpdateTransmitDescRingData() at UpdateTransmitDescRingData+0xd3
I think this can cause a deadlock an a box with 2 sk(4) interfaces if
the 2 interfaces free a buffer allocated by the other at the same time.
A patch is attached (use an sk_jlist_mtx).
* When compiling if_sk as a module and unloading it, there seems to be
a few leaks.
A patch that fixes some of them is attached, but there is probably more
leaks.
Especially mii_phy_probe() and miibus_probe() allocate things during
a probe routine without freeing them and I suspect it's bad.
>How-To-Repeat:
* Enable witness on a box that acts as a gateway.
* Do kldload/kldunload if_sk and look at vmstat -m|grep devbuf.
>Fix:
--- sk.patch begins here ---
Index: if_sk.c
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_sk.c,v
retrieving revision 1.94
diff -u -r1.94 if_sk.c
--- if_sk.c 24 Dec 2004 14:13:38 -0000 1.94
+++ if_sk.c 30 Dec 2004 21:43:06 -0000
@@ -1041,6 +1041,7 @@
SLIST_INIT(&sc_if->sk_jfree_listhead);
SLIST_INIT(&sc_if->sk_jinuse_listhead);
+ mtx_init(&sc_if->sk_jlist_mtx, "sk_jlist_mtx", NULL, MTX_DEF);
/*
* Now divide it up into 9K pieces and save the addresses
@@ -1053,8 +1054,15 @@
entry = malloc(sizeof(struct sk_jpool_entry),
M_DEVBUF, M_NOWAIT);
if (entry == NULL) {
- free(sc_if->sk_cdata.sk_jumbo_buf, M_DEVBUF);
+ while (!SLIST_EMPTY(&sc_if->sk_jfree_listhead)) {
+ entry = SLIST_FIRST(&sc_if->sk_jfree_listhead);
+ SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries);
+ free(entry, M_DEVBUF);
+ }
+ contigfree(sc_if->sk_cdata.sk_jumbo_buf, SK_JMEM,
+ M_DEVBUF);
sc_if->sk_cdata.sk_jumbo_buf = NULL;
+ mtx_destroy(&sc_if->sk_jlist_mtx);
printf("sk%d: no memory for jumbo "
"buffer queue!\n", sc_if->sk_unit);
return(ENOBUFS);
@@ -1076,7 +1084,7 @@
{
struct sk_jpool_entry *entry;
- SK_IF_LOCK_ASSERT(sc_if);
+ SK_JLIST_LOCK(sc_if);
entry = SLIST_FIRST(&sc_if->sk_jfree_listhead);
@@ -1089,6 +1097,9 @@
SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries);
SLIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead, entry, jpool_entries);
+
+ SK_JLIST_UNLOCK(sc_if);
+
return(sc_if->sk_cdata.sk_jslots[entry->slot]);
}
@@ -1109,7 +1120,7 @@
if (sc_if == NULL)
panic("sk_jfree: didn't get softc pointer!");
- SK_IF_LOCK(sc_if);
+ SK_JLIST_LOCK(sc_if);
/* calculate the slot this buffer belongs to */
i = ((vm_offset_t)buf
@@ -1125,7 +1136,7 @@
SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, jpool_entries);
SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, entry, jpool_entries);
- SK_IF_UNLOCK(sc_if);
+ SK_JLIST_UNLOCK(sc_if);
return;
}
@@ -1737,8 +1748,21 @@
device_delete_child(dev, sc_if->sk_miibus);
*/
bus_generic_detach(dev);
- if (sc_if->sk_cdata.sk_jumbo_buf != NULL)
+ if (sc_if->sk_cdata.sk_jumbo_buf != NULL) {
+ struct sk_jpool_entry *entry;
+ while (!SLIST_EMPTY(&sc_if->sk_jfree_listhead)) {
+ entry = SLIST_FIRST(&sc_if->sk_jfree_listhead);
+ SLIST_REMOVE_HEAD(&sc_if->sk_jfree_listhead, jpool_entries);
+ free(entry, M_DEVBUF);
+ }
+ while (!SLIST_EMPTY(&sc_if->sk_jinuse_listhead)) {
+ entry = SLIST_FIRST(&sc_if->sk_jinuse_listhead);
+ SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, jpool_entries);
+ free(entry, M_DEVBUF);
+ }
contigfree(sc_if->sk_cdata.sk_jumbo_buf, SK_JMEM, M_DEVBUF);
+ mtx_destroy(&sc_if->sk_jlist_mtx);
+ }
if (sc_if->sk_rdata != NULL) {
contigfree(sc_if->sk_rdata, sizeof(struct sk_ring_data),
M_DEVBUF);
Index: if_skreg.h
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_skreg.h,v
retrieving revision 1.24
diff -u -r1.24 if_skreg.h
--- if_skreg.h 15 Nov 2004 19:37:21 -0000 1.24
+++ if_skreg.h 30 Dec 2004 17:42:22 -0000
@@ -1468,8 +1468,12 @@
int sk_if_flags;
SLIST_HEAD(__sk_jfreehead, sk_jpool_entry) sk_jfree_listhead;
SLIST_HEAD(__sk_jinusehead, sk_jpool_entry) sk_jinuse_listhead;
+ struct mtx sk_jlist_mtx;
};
+#define SK_JLIST_LOCK(_sc) mtx_lock(&(_sc)->sk_jlist_mtx)
+#define SK_JLIST_UNLOCK(_sc) mtx_unlock(&(_sc)->sk_jlist_mtx)
+
#define SK_MAXUNIT 256
#define SK_TIMEOUT 1000
#define ETHER_ALIGN 2
--- sk.patch ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200412302343.iBUNhOAD001307>
