diff options
author | bz <bz@FreeBSD.org> | 2005-03-17 14:27:22 +0000 |
---|---|---|
committer | bz <bz@FreeBSD.org> | 2005-03-17 14:27:22 +0000 |
commit | 63691d918e48d1eaf923390178696885f14fa240 (patch) | |
tree | 55ecf4eb60058ba8a03eba1c891267f63c4cb8fb /sys/pci/if_sk.c | |
parent | e2f49ebf076060ca0bc87c59da336c3d2fa55f6a (diff) | |
download | FreeBSD-src-63691d918e48d1eaf923390178696885f14fa240.zip FreeBSD-src-63691d918e48d1eaf923390178696885f14fa240.tar.gz |
Do not try to free non allocated memory in error case.
Do our best to plug some memory leaks (VPD data, jumbo memory buffer,...).
Log if we cannot free because memory still in use[1].
Change locking to avoid ''acquiring duplicate lock of same
type: "network driver"'' and potential deadlock. Also seems to fix LOR #063.
[1] This change does not solve problems if buffers are still in use when
unloading if_sk.ko. There is ongoing work which will address jumbogram
allocations in a more general way.
PR: kern/75677 (with changes, no mii fixes in here)
Tested by: net, Antoine Brodin (slightly different version)
Approved by: rwatson (mentor)
MFC after: 5 days
Diffstat (limited to 'sys/pci/if_sk.c')
-rw-r--r-- | sys/pci/if_sk.c | 68 |
1 files changed, 56 insertions, 12 deletions
diff --git a/sys/pci/if_sk.c b/sys/pci/if_sk.c index 16e0c41..b7b9e47 100644 --- a/sys/pci/if_sk.c +++ b/sys/pci/if_sk.c @@ -208,6 +208,7 @@ static void sk_reset(struct sk_softc *); static int sk_newbuf(struct sk_if_softc *, struct sk_chain *, struct mbuf *); static int sk_alloc_jumbo_mem(struct sk_if_softc *); +static void sk_free_jumbo_mem(struct sk_if_softc *); static void *sk_jalloc(struct sk_if_softc *); static void sk_jfree(void *, void *); static int sk_init_rx_ring(struct sk_if_softc *); @@ -1057,6 +1058,8 @@ sk_alloc_jumbo_mem(sc_if) return(ENOBUFS); } + mtx_init(&sc_if->sk_jlist_mtx, "sk_jlist_mtx", NULL, MTX_DEF); + SLIST_INIT(&sc_if->sk_jfree_listhead); SLIST_INIT(&sc_if->sk_jinuse_listhead); @@ -1071,7 +1074,7 @@ sk_alloc_jumbo_mem(sc_if) entry = malloc(sizeof(struct sk_jpool_entry), M_DEVBUF, M_NOWAIT); if (entry == NULL) { - free(sc_if->sk_cdata.sk_jumbo_buf, M_DEVBUF); + sk_free_jumbo_mem(sc_if); sc_if->sk_cdata.sk_jumbo_buf = NULL; printf("sk%d: no memory for jumbo " "buffer queue!\n", sc_if->sk_unit); @@ -1085,6 +1088,36 @@ sk_alloc_jumbo_mem(sc_if) return(0); } +static void +sk_free_jumbo_mem(sc_if) + struct sk_if_softc *sc_if; +{ + struct sk_jpool_entry *entry; + + SK_JLIST_LOCK(sc_if); + + /* We cannot release external mbuf storage while in use. */ + if (!SLIST_EMPTY(&sc_if->sk_jinuse_listhead)) { + printf("sk%d: will leak jumbo buffer memory!\n", sc_if->sk_unit); + SK_JLIST_UNLOCK(sc_if); + return; + } + + 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); + } + + SK_JLIST_UNLOCK(sc_if); + + mtx_destroy(&sc_if->sk_jlist_mtx); + + contigfree(sc_if->sk_cdata.sk_jumbo_buf, SK_JMEM, M_DEVBUF); + + return; +} + /* * Allocate a jumbo buffer. */ @@ -1094,7 +1127,7 @@ sk_jalloc(sc_if) { struct sk_jpool_entry *entry; - SK_IF_LOCK_ASSERT(sc_if); + SK_JLIST_LOCK(sc_if); entry = SLIST_FIRST(&sc_if->sk_jfree_listhead); @@ -1102,11 +1135,15 @@ sk_jalloc(sc_if) #ifdef SK_VERBOSE printf("sk%d: no free jumbo buffers\n", sc_if->sk_unit); #endif + SK_JLIST_UNLOCK(sc_if); return(NULL); } 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]); } @@ -1127,7 +1164,7 @@ sk_jfree(buf, args) 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 @@ -1142,8 +1179,10 @@ sk_jfree(buf, args) entry->slot = i; SLIST_REMOVE_HEAD(&sc_if->sk_jinuse_listhead, jpool_entries); SLIST_INSERT_HEAD(&sc_if->sk_jfree_listhead, entry, jpool_entries); + if (SLIST_EMPTY(&sc_if->sk_jinuse_listhead)) + wakeup(sc_if); - SK_IF_UNLOCK(sc_if); + SK_JLIST_UNLOCK(sc_if); return; } @@ -1369,8 +1408,6 @@ sk_attach(dev) sc_if = device_get_softc(dev); sc = device_get_softc(device_get_parent(dev)); port = *(int *)device_get_ivars(dev); - free(device_get_ivars(dev), M_DEVBUF); - device_set_ivars(dev, NULL); sc_if->sk_dev = dev; sc_if->sk_unit = device_get_unit(dev); @@ -1384,7 +1421,7 @@ sk_attach(dev) /* Allocate the descriptor queues. */ sc_if->sk_rdata = contigmalloc(sizeof(struct sk_ring_data), M_DEVBUF, - M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); + M_NOWAIT, M_ZERO, 0xffffffff, PAGE_SIZE, 0); if (sc_if->sk_rdata == NULL) { printf("sk%d: no memory for list buffers!\n", sc_if->sk_unit); @@ -1392,8 +1429,6 @@ sk_attach(dev) goto fail; } - bzero(sc_if->sk_rdata, sizeof(struct sk_ring_data)); - /* Try to allocate memory for jumbo buffers. */ if (sk_alloc_jumbo_mem(sc_if)) { printf("sk%d: jumbo buffer allocation failed\n", @@ -1854,7 +1889,7 @@ sk_detach(dev) */ bus_generic_detach(dev); if (sc_if->sk_cdata.sk_jumbo_buf != NULL) - contigfree(sc_if->sk_cdata.sk_jumbo_buf, SK_JMEM, M_DEVBUF); + sk_free_jumbo_mem(sc_if); if (sc_if->sk_rdata != NULL) { contigfree(sc_if->sk_rdata, sizeof(struct sk_ring_data), M_DEVBUF); @@ -1874,13 +1909,22 @@ skc_detach(dev) KASSERT(mtx_initialized(&sc->sk_mtx), ("sk mutex not initialized")); if (device_is_alive(dev)) { - if (sc->sk_devs[SK_PORT_A] != NULL) + if (sc->sk_devs[SK_PORT_A] != NULL) { + free(device_get_ivars(sc->sk_devs[SK_PORT_A]), M_DEVBUF); device_delete_child(dev, sc->sk_devs[SK_PORT_A]); - if (sc->sk_devs[SK_PORT_B] != NULL) + } + if (sc->sk_devs[SK_PORT_B] != NULL) { + free(device_get_ivars(sc->sk_devs[SK_PORT_B]), M_DEVBUF); device_delete_child(dev, sc->sk_devs[SK_PORT_B]); + } bus_generic_detach(dev); } + if (sc->sk_vpd_prodname != NULL) + free(sc->sk_vpd_prodname, M_DEVBUF); + if (sc->sk_vpd_readonly != NULL) + free(sc->sk_vpd_readonly, M_DEVBUF); + if (sc->sk_intrhand) bus_teardown_intr(dev, sc->sk_irq, sc->sk_intrhand); if (sc->sk_irq) |