summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornp <np@FreeBSD.org>2014-07-31 23:04:41 +0000
committernp <np@FreeBSD.org>2014-07-31 23:04:41 +0000
commit072ac2f2da086a7f38f0374707f6c98a21aaf15e (patch)
tree05789cb6eda8c7fa52a3025f4990823fc8c81e87
parentf850608aee29e7e8e964d6526a571a6cf7609200 (diff)
downloadFreeBSD-src-072ac2f2da086a7f38f0374707f6c98a21aaf15e.zip
FreeBSD-src-072ac2f2da086a7f38f0374707f6c98a21aaf15e.tar.gz
MFC r268971 and r269032.
r268971: Simplify r267600, there's no need to distinguish between allocated and inlined mbufs. r269032: cxgbe(4): Keep track of the clusters that have to be freed by the custom free routine (rxb_free) in the driver. Fail MOD_UNLOAD with EBUSY if any such cluster has been handed up to the kernel but hasn't been freed yet. This prevents a panic later when the cluster finally needs to be freed but rxb_free is gone from the kernel.
-rw-r--r--sys/dev/cxgbe/adapter.h5
-rw-r--r--sys/dev/cxgbe/t4_main.c79
-rw-r--r--sys/dev/cxgbe/t4_sge.c51
3 files changed, 99 insertions, 36 deletions
diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h
index a4f729c..0a986ec 100644
--- a/sys/dev/cxgbe/adapter.h
+++ b/sys/dev/cxgbe/adapter.h
@@ -254,8 +254,7 @@ struct cluster_metadata {
struct fl_sdesc {
caddr_t cl;
- uint8_t nimbuf; /* # of inline mbufs with ref on the cluster */
- uint8_t nembuf; /* # of allocated mbufs with ref */
+ uint16_t nmbuf; /* # of driver originated mbufs with ref on cluster */
struct cluster_layout cll;
};
@@ -852,6 +851,8 @@ void end_synchronized_op(struct adapter *, int);
/* t4_sge.c */
void t4_sge_modload(void);
+void t4_sge_modunload(void);
+uint64_t t4_sge_extfree_refs(void);
void t4_init_sge_cpl_handlers(struct adapter *);
void t4_tweak_chip_settings(struct adapter *);
int t4_read_chip_settings(struct adapter *);
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 8a7d041..8e8fdc5 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -8090,6 +8090,9 @@ tweak_tunables(void)
t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX;
}
+static struct sx mlu; /* mod load unload */
+SX_SYSINIT(cxgbe_mlu, &mlu, "cxgbe mod load/unload");
+
static int
mod_event(module_t mod, int cmd, void *arg)
{
@@ -8098,41 +8101,67 @@ mod_event(module_t mod, int cmd, void *arg)
switch (cmd) {
case MOD_LOAD:
- if (atomic_fetchadd_int(&loaded, 1))
- break;
- t4_sge_modload();
- sx_init(&t4_list_lock, "T4/T5 adapters");
- SLIST_INIT(&t4_list);
+ sx_xlock(&mlu);
+ if (loaded++ == 0) {
+ t4_sge_modload();
+ sx_init(&t4_list_lock, "T4/T5 adapters");
+ SLIST_INIT(&t4_list);
#ifdef TCP_OFFLOAD
- sx_init(&t4_uld_list_lock, "T4/T5 ULDs");
- SLIST_INIT(&t4_uld_list);
+ sx_init(&t4_uld_list_lock, "T4/T5 ULDs");
+ SLIST_INIT(&t4_uld_list);
#endif
- t4_tracer_modload();
- tweak_tunables();
+ t4_tracer_modload();
+ tweak_tunables();
+ }
+ sx_xunlock(&mlu);
break;
case MOD_UNLOAD:
- if (atomic_fetchadd_int(&loaded, -1) > 1)
- break;
- t4_tracer_modunload();
+ sx_xlock(&mlu);
+ if (--loaded == 0) {
+ int tries;
+
+ sx_slock(&t4_list_lock);
+ if (!SLIST_EMPTY(&t4_list)) {
+ rc = EBUSY;
+ sx_sunlock(&t4_list_lock);
+ goto done_unload;
+ }
+#ifdef TCP_OFFLOAD
+ sx_slock(&t4_uld_list_lock);
+ if (!SLIST_EMPTY(&t4_uld_list)) {
+ rc = EBUSY;
+ sx_sunlock(&t4_uld_list_lock);
+ sx_sunlock(&t4_list_lock);
+ goto done_unload;
+ }
+#endif
+ tries = 0;
+ while (tries++ < 5 && t4_sge_extfree_refs() != 0) {
+ uprintf("%ju clusters with custom free routine "
+ "still is use.\n", t4_sge_extfree_refs());
+ pause("t4unload", 2 * hz);
+ }
#ifdef TCP_OFFLOAD
- sx_slock(&t4_uld_list_lock);
- if (!SLIST_EMPTY(&t4_uld_list)) {
- rc = EBUSY;
sx_sunlock(&t4_uld_list_lock);
- break;
- }
- sx_sunlock(&t4_uld_list_lock);
- sx_destroy(&t4_uld_list_lock);
#endif
- sx_slock(&t4_list_lock);
- if (!SLIST_EMPTY(&t4_list)) {
- rc = EBUSY;
sx_sunlock(&t4_list_lock);
- break;
+
+ if (t4_sge_extfree_refs() == 0) {
+ t4_tracer_modunload();
+#ifdef TCP_OFFLOAD
+ sx_destroy(&t4_uld_list_lock);
+#endif
+ sx_destroy(&t4_list_lock);
+ t4_sge_modunload();
+ loaded = 0;
+ } else {
+ rc = EBUSY;
+ loaded++; /* undo earlier decrement */
+ }
}
- sx_sunlock(&t4_list_lock);
- sx_destroy(&t4_list_lock);
+done_unload:
+ sx_xunlock(&mlu);
break;
}
diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c
index 9bdc446..9b47ff0 100644
--- a/sys/dev/cxgbe/t4_sge.c
+++ b/sys/dev/cxgbe/t4_sge.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <sys/sysctl.h>
#include <sys/smp.h>
+#include <sys/counter.h>
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/if.h>
@@ -242,6 +243,9 @@ static int handle_fw_msg(struct sge_iq *, const struct rss_header *,
static int sysctl_uint16(SYSCTL_HANDLER_ARGS);
static int sysctl_bufsizes(SYSCTL_HANDLER_ARGS);
+static counter_u64_t extfree_refs;
+static counter_u64_t extfree_rels;
+
/*
* Called on MOD_LOAD. Validates and calculates the SGE tunables.
*/
@@ -313,6 +317,30 @@ t4_sge_modload(void)
" using 0 instead.\n", cong_drop);
cong_drop = 0;
}
+
+ extfree_refs = counter_u64_alloc(M_WAITOK);
+ extfree_rels = counter_u64_alloc(M_WAITOK);
+ counter_u64_zero(extfree_refs);
+ counter_u64_zero(extfree_rels);
+}
+
+void
+t4_sge_modunload(void)
+{
+
+ counter_u64_free(extfree_refs);
+ counter_u64_free(extfree_rels);
+}
+
+uint64_t
+t4_sge_extfree_refs(void)
+{
+ uint64_t refs, rels;
+
+ rels = counter_u64_fetch(extfree_rels);
+ refs = counter_u64_fetch(extfree_refs);
+
+ return (refs - rels);
}
void
@@ -1450,6 +1478,7 @@ rxb_free(struct mbuf *m, void *arg1, void *arg2)
caddr_t cl = arg2;
uma_zfree(zone, cl);
+ counter_u64_add(extfree_rels, 1);
return (EXT_FREE_OK);
}
@@ -1498,7 +1527,7 @@ get_scatter_segment(struct adapter *sc, struct sge_fl *fl, int total, int flags)
/* copy data to mbuf */
bcopy(payload, mtod(m, caddr_t), len);
- } else if (sd->nimbuf * MSIZE < cll->region1) {
+ } else if (sd->nmbuf * MSIZE < cll->region1) {
/*
* There's spare room in the cluster for an mbuf. Create one
@@ -1506,14 +1535,15 @@ get_scatter_segment(struct adapter *sc, struct sge_fl *fl, int total, int flags)
*/
MPASS(clm != NULL);
- m = (struct mbuf *)(sd->cl + sd->nimbuf * MSIZE);
+ m = (struct mbuf *)(sd->cl + sd->nmbuf * MSIZE);
/* No bzero required */
if (m_init(m, NULL, 0, M_NOWAIT, MT_DATA, flags | M_NOFREE))
return (NULL);
fl->mbuf_inlined++;
m_extaddref(m, payload, padded_len, &clm->refcount, rxb_free,
swz->zone, sd->cl);
- sd->nimbuf++;
+ if (sd->nmbuf++ == 0)
+ counter_u64_add(extfree_refs, 1);
} else {
@@ -1530,7 +1560,8 @@ get_scatter_segment(struct adapter *sc, struct sge_fl *fl, int total, int flags)
if (clm != NULL) {
m_extaddref(m, payload, padded_len, &clm->refcount,
rxb_free, swz->zone, sd->cl);
- sd->nembuf++;
+ if (sd->nmbuf++ == 0)
+ counter_u64_add(extfree_refs, 1);
} else {
m_cljset(m, sd->cl, swz->type);
sd->cl = NULL; /* consumed, not a recycle candidate */
@@ -3055,7 +3086,7 @@ refill_fl(struct adapter *sc, struct sge_fl *fl, int nbufs)
if (sd->cl != NULL) {
- if (sd->nimbuf + sd->nembuf == 0) {
+ if (sd->nmbuf == 0) {
/*
* Fast recycle without involving any atomics on
* the cluster's metadata (if the cluster has
@@ -3082,6 +3113,7 @@ refill_fl(struct adapter *sc, struct sge_fl *fl, int nbufs)
if (atomic_fetchadd_int(&clm->refcount, -1) == 1) {
fl->cl_recycled++;
+ counter_u64_add(extfree_rels, 1);
goto recycled;
}
sd->cl = NULL; /* gave up my reference */
@@ -3114,8 +3146,7 @@ recycled:
#endif
clm->refcount = 1;
}
- sd->nimbuf = 0;
- sd->nembuf = 0;
+ sd->nmbuf = 0;
recycled_fast:
fl->pending++;
fl->needed--;
@@ -3184,9 +3215,11 @@ free_fl_sdesc(struct adapter *sc, struct sge_fl *fl)
cll = &sd->cll;
clm = cl_metadata(sc, fl, cll, sd->cl);
- if (sd->nimbuf + sd->nembuf == 0 ||
- (clm && atomic_fetchadd_int(&clm->refcount, -1) == 1)) {
+ if (sd->nmbuf == 0)
+ uma_zfree(sc->sge.sw_zone_info[cll->zidx].zone, sd->cl);
+ else if (clm && atomic_fetchadd_int(&clm->refcount, -1) == 1) {
uma_zfree(sc->sge.sw_zone_info[cll->zidx].zone, sd->cl);
+ counter_u64_add(extfree_rels, 1);
}
sd->cl = NULL;
}
OpenPOWER on IntegriCloud