freebsd_network: Fix destruction of ref-counted ext_bufs.

The check as to whether or not the buf should be freed was wrong,
leading to incorrect frees.

Fixes double-free KDLs under the idualwifi driver that occur
on boot extremely frequently.

Change-Id: Ia411a6f5c31dd30764705cd87840797f862b4020
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2862
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2020-06-02 03:13:59 +00:00
committed by waddlesplash
parent 3ac5d98070
commit a68e59dd1d
+16 -15
View File
@@ -235,7 +235,6 @@ m_cljget(struct mbuf* memoryBuffer, int how, int size)
static void static void
mb_free_ext(struct mbuf *memoryBuffer) mb_free_ext(struct mbuf *memoryBuffer)
{ {
object_cache *cache = NULL;
volatile u_int *refcnt; volatile u_int *refcnt;
struct mbuf *mref; struct mbuf *mref;
int freembuf; int freembuf;
@@ -270,22 +269,24 @@ mb_free_ext(struct mbuf *memoryBuffer)
freembuf = 1; freembuf = 1;
/* Free attached storage only if this mbuf is the only reference to it. */ /* Free attached storage only if this mbuf is the only reference to it. */
if (!(*refcnt == 1 || atomic_add(refcnt, -1) == 1) if (*refcnt == 1 || atomic_add((int32*)refcnt, -1) == 1) {
&& !(freembuf && memoryBuffer != mref)) object_cache *cache = NULL;
return;
if (memoryBuffer->m_ext.ext_type == EXT_CLUSTER) if (memoryBuffer->m_ext.ext_type == EXT_CLUSTER)
cache = sChunkCache; cache = sChunkCache;
else if (memoryBuffer->m_ext.ext_type == EXT_JUMBO9) else if (memoryBuffer->m_ext.ext_type == EXT_JUMBO9)
cache = sJumbo9ChunkCache; cache = sJumbo9ChunkCache;
else if (memoryBuffer->m_ext.ext_type == EXT_JUMBOP) else if (memoryBuffer->m_ext.ext_type == EXT_JUMBOP)
cache = sJumboPageSizeCache; cache = sJumboPageSizeCache;
else else
panic("unknown mbuf ext_type %d", memoryBuffer->m_ext.ext_type); panic("unknown mbuf ext_type %d", memoryBuffer->m_ext.ext_type);
object_cache_free(cache, memoryBuffer->m_ext.ext_buf, 0); object_cache_free(cache, memoryBuffer->m_ext.ext_buf, 0);
memoryBuffer->m_ext.ext_buf = NULL; object_cache_free(sMBufCache, mref, 0);
object_cache_free(sMBufCache, memoryBuffer, 0); }
if (freembuf && memoryBuffer != mref)
object_cache_free(sMBufCache, memoryBuffer, 0);
} }