Eliminate a race in MEXTFREE(). The reference counter decrement and test

was not atomic. We now make sure that we free the ext buf if the reference
count is about to reach 0 but also make sure that nobody else has done it
before us.

While I'm here, change refcnt to u_int (from long). This fixes a compiler
warning regarding use of atomic_cmpset_long on i386.

Submitted by: jasone
Reviewed by: jlemon, jake
This commit is contained in:
Bosko Milekic 2000-12-13 05:13:02 +00:00
parent f6a99e61c5
commit 988cb8dfd9

View File

@ -244,7 +244,7 @@ union mcluster {
*/
union mext_refcnt {
union mext_refcnt *next_ref;
u_long refcnt;
u_int refcnt;
};
/*
@ -293,10 +293,10 @@ struct mcntfree_lst {
#define MEXT_REM_REF(m) do { \
KASSERT((m)->m_ext.ref_cnt->refcnt > 0, ("m_ext refcnt < 0")); \
atomic_subtract_long(&((m)->m_ext.ref_cnt->refcnt), 1); \
atomic_subtract_int(&((m)->m_ext.ref_cnt->refcnt), 1); \
} while(0)
#define MEXT_ADD_REF(m) atomic_add_long(&((m)->m_ext.ref_cnt->refcnt), 1)
#define MEXT_ADD_REF(m) atomic_add_int(&((m)->m_ext.ref_cnt->refcnt), 1)
#define _MEXT_ALLOC_CNT(m_cnt, how) do { \
union mext_refcnt *__mcnt; \
@ -483,17 +483,22 @@ struct mcntfree_lst {
mtx_exit(&mclfree.m_mtx, MTX_DEF); \
} while (0)
/* MEXTFREE:
* If the atomic_cmpset_int() returns 0, then we effectively do nothing
* in terms of "cleaning up" (freeing the ext buf and ref. counter) as
* this means that either there are still references, or another thread
* is taking care of the clean-up.
*/
#define MEXTFREE(m) do { \
struct mbuf *_mmm = (m); \
\
if (MEXT_IS_REF(_mmm)) \
MEXT_REM_REF(_mmm); \
else if (_mmm->m_ext.ext_type != EXT_CLUSTER) { \
(*(_mmm->m_ext.ext_free))(_mmm->m_ext.ext_buf, \
_mmm->m_ext.ext_args); \
_MEXT_DEALLOC_CNT(_mmm->m_ext.ref_cnt); \
} else { \
_MCLFREE(_mmm->m_ext.ext_buf); \
MEXT_REM_REF(_mmm); \
if (atomic_cmpset_int(&_mmm->m_ext.ref_cnt->refcnt, 0, 1)) { \
if (_mmm->m_ext.ext_type != EXT_CLUSTER) { \
(*(_mmm->m_ext.ext_free))(_mmm->m_ext.ext_buf, \
_mmm->m_ext.ext_args); \
} else \
_MCLFREE(_mmm->m_ext.ext_buf); \
_MEXT_DEALLOC_CNT(_mmm->m_ext.ref_cnt); \
} \
_mmm->m_flags &= ~M_EXT; \