【发布时间】:2021-01-27 01:50:18
【问题描述】:
前言:
如果您熟悉用于管理网络数据包的 linux 内核缓冲区,即 sk_buff,那么您可能知道释放 skb 的函数:__kfree_skb()
根据我对sk_buff 代码和API 的理解,__kfree_skb() 是释放sk_buff 的函数。它是一个内部辅助函数,理论上用户不应该调用它 - 用户应该调用它的一个包装器函数,例如 kfree_skb() 或 consume_skb()(或其他一些安全包装器)。
在调用__kfree_skb()之前,包装函数应该检查并减少sk_buff的引用计数,如果达到0,包装函数可以调用__kfree_skb()释放sk_buff。一些包装器自己完成,而另一些则调用 skb_unref()(大约 3 年前已添加到主线)。
希望你还在我身边。在这里我要说到点子上了。我最近注意到skb_unref() 没有做我认为应该做的事情。直到最新版本的 linux kernel v5.8,skb_unref() 看起来是这样的:
/**
* skb_unref - decrement the skb's reference count
* @skb: buffer
*
* Returns true if we can free the skb.
*/
static inline bool skb_unref(struct sk_buff *skb)
{
if (unlikely(!skb))
return false;
if (likely(refcount_read(&skb->users) == 1))
smp_rmb();
else if (likely(!refcount_dec_and_test(&skb->users)))
return false;
return true;
}
问题:
- 阅读代码后,我注意到如果
refcount_read返回1,我们不会将skb->users减为0,但函数确实返回true。 - 这意味着,如果
refcount_read返回 1,skb_unref()告诉kfree_skb()(或其他使用skb_unref()的包装函数)它可以释放skb(但它不会减少@987654344 @ 到 0),如果最后一个真正释放 skb 的用户在调用kfree_skb()之后没有费心将skb设置为NULL,那么当其他一些用户将检查这个skb引用计数时,它可能不小心再次尝试释放它! - 我还确保我没有看错代码,我只是尝试调用
kfree_skb()两次,然后一切都崩溃了...... - 我错了吗?也许我不明白如何正确使用
kfree_skb()/skb_unref()?我只是想知道,如果kfree_skb()/skb_unref()没有按应有的方式行事,那到底是怎么回事。
【问题讨论】:
标签: c linux linux-kernel network-programming linux-device-driver