The m_ext reference counts are potentially shared and modified
asynchronously by different threads. Thus, declare as volatile the reference count that is accessed through m_ext's pointer, ref_cnt. Revert the previous change, revision 1.144, that casts as volatile a single dereference of ref_cnt. Reviewed by: bmilekic, dwhite Problem reported by: kris MFC after: 3 days
This commit is contained in:
parent
22a9eb5334
commit
2b2c7a6b40
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=143188
@ -199,7 +199,7 @@ m_extadd(struct mbuf *mb, caddr_t buf, u_int size,
|
||||
ref_cnt = (u_int *)uma_find_refcnt(zone_clust,
|
||||
mb->m_ext.ext_buf);
|
||||
else if (type == EXT_EXTREF)
|
||||
ref_cnt = mb->m_ext.ref_cnt;
|
||||
ref_cnt = __DEVOLATILE(u_int *, mb->m_ext.ref_cnt);
|
||||
mb->m_ext.ref_cnt = (ref_cnt == NULL) ?
|
||||
malloc(sizeof(u_int), M_MBUF, M_NOWAIT) : (u_int *)ref_cnt;
|
||||
if (mb->m_ext.ref_cnt != NULL) {
|
||||
@ -234,12 +234,9 @@ mb_free_ext(struct mbuf *m)
|
||||
* This is tricky. We need to make sure to decrement the
|
||||
* refcount in a safe way but to also clean up if we're the
|
||||
* last reference. This method seems to do it without race.
|
||||
* The volatile cast is required to emit the proper load
|
||||
* instructions. Otherwise gcc will optimize the read outside
|
||||
* of the while loop.
|
||||
*/
|
||||
while (dofree == 0) {
|
||||
cnt = *(volatile u_int *)(m->m_ext.ref_cnt);
|
||||
cnt = *(m->m_ext.ref_cnt);
|
||||
if (atomic_cmpset_int(m->m_ext.ref_cnt, cnt, cnt - 1)) {
|
||||
if (cnt == 1)
|
||||
dofree = 1;
|
||||
@ -262,7 +259,8 @@ mb_free_ext(struct mbuf *m)
|
||||
m->m_ext.ext_args);
|
||||
if (m->m_ext.ext_type != EXT_EXTREF) {
|
||||
if (m->m_ext.ref_cnt != NULL)
|
||||
free(m->m_ext.ref_cnt, M_MBUF);
|
||||
free(__DEVOLATILE(u_int *,
|
||||
m->m_ext.ref_cnt), M_MBUF);
|
||||
m->m_ext.ref_cnt = NULL;
|
||||
}
|
||||
m->m_ext.ext_buf = NULL;
|
||||
|
@ -122,7 +122,7 @@ struct m_ext {
|
||||
(void *, void *);
|
||||
void *ext_args; /* optional argument pointer */
|
||||
u_int ext_size; /* size of buffer, for ext_free */
|
||||
u_int *ref_cnt; /* pointer to ref count info */
|
||||
volatile u_int *ref_cnt; /* pointer to ref count info */
|
||||
int ext_type; /* type of external storage */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user