承接上一篇blog--sk_buff整理笔记(二、操作函数),这篇是要来讲解下sk_buff结构的内存申请和释放函数。因为sk_buff结构是比较复杂的(并不是其本身结构复杂,而是其所指的数据区以及分片结构等,合在一起就变复杂了),所以在内存申请和释放时,就要搞清楚什么函数对应的申请分配或释放什么结构内存。这里不提倡自己用kmalloc()和kfree()函数来为sk_buff相关结构体申请内存及销毁,而要用内核提供好的一些函数去为这些结构体申请内存。内核开发的原则:尽量用内核定义好的数据和函数以及操作宏,不到迫不得已不要自行定义任何东西。这样做是为了接口统一,移植方便,容易维护。
第一、sk_buff结构的内存申请:
static inline struct sk_buff *alloc_skb(unsigned int size,
gfp_t priority)
{
return __alloc_skb(size, priority, 0, -1);
}
static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
gfp_t priority)
{
return __alloc_skb(size, priority, 1, -1);
}
struct sk_buff *dev_alloc_skb(unsigned int length)
{
/*
* There is more code here than it seems:
* __dev_alloc_skb is an inline
*/
return __dev_alloc_skb(length, GFP_ATOMIC);
}
static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
gfp_t gfp_mask)
{
struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask);
if (likely(skb))
skb_reserve(skb, NET_SKB_PAD);
return skb;
}
这几个函数都是在linux-2.6.32.63\include\linux\sk_buff.h文件中的,其实就函数也可以看得出这是内联函数。不记得在前面讲过没,对于简洁常用的函数一般都定义为内联函数,这样做是为了提高CPU工作效率和内存利用率。一般的函数调用要保存现场(在堆栈中保存调用函数时现场状态,包括地址,执行状态等);当调用函数完后,又要恢复现场状态(把开始保存的状态数据从堆栈中读取出来)。在调用函数和返回时,浪费了CPU很多时间,再个在存储时也会出现些碎片。所以再使用简洁函数时,一般定义为内联函数,在函数前面加个inline关键字。
讲了内联函数细节后,来看下上面这几个内存申请函数。发现这几个函数其实本质上都是封装了 __alloc_skb();函数,那么首先就要来分析下__alloc_skb()函数,然后再去分析下这几个函数的异同点,以方便在申请sk_buff结构时,该用哪个函数去申请。
struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
int fclone, int node)
{
struct kmem_cache *cache;
struct skb_shared_info *shinfo;
struct sk_