Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1685921
  • 博文数量: 511
  • 博客积分: 967
  • 博客等级: 准尉
  • 技术积分: 2560
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-06 14:19
文章分类

全部博文(511)

文章存档

2016年(11)

2015年(61)

2014年(257)

2013年(63)

2012年(119)

分类: LINUX

2014-05-17 22:37:12

本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
    

今天开始再次研究sk_buff,想继续研究linux,重要的是基础,基础,还是基础!

首先看alloc_skb
  1. static inline struct sk_buff *alloc_skb(unsigned int size,
  2.                     gfp_t priority)
  3. {
  4.     return __alloc_skb(size, priority, 0, -1);
  5. }
这个函数比较简单,参数中的size不用解释,为skb数据段的大小,但是第二个参数priority名字比较奇怪。叫优先级,实际上则是GFP MASK宏,如GFP_KERNEL,GFP_ATOMIC等。有些不解。。。

接下来看__alloc_skb
  1. /*
  2. 参数:
  3. size:skb的数据大小
  4. gfp_mask:不用解释
  5. fclone:表示从哪个cache中分配
  6.        当fclone为1时,从skbuff_fclone_cache上分配
  7.        当fclone为0时,从skbuff_head_cache上分配
  8. node: NUMA节点
  9. */
  10. struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
  11.              int fclone, int node)
  12. {
  13.     struct kmem_cache *cache;
  14.     struct skb_shared_info *shinfo;
  15.     struct sk_buff *skb;
  16.     u8 *data;
     /* 获得指定的cache */
  1.     cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;
     /* 从cache上分配, 如果cache上无法分配,则从内存中申请 */
  1.     /* Get the HEAD */
  2.     skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
  3.     if (!skb)
  4.         goto out;
  5.     prefetchw(skb);

  6.     size = SKB_DATA_ALIGN(size);
  7.     data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),
  8.             gfp_mask, node);
  9.     if (!data)
  10.         goto nodata;
  11.     prefetchw(data + size);

  12.     /*
  13.      * Only clear those fields we need to clear, not those that we will
  14.      * actually initialise below. Hence, don't put any more fields after
  15.      * the tail pointer in struct
  16.      */
  17.     memset(skb, 0, offsetof(struct sk_buff, tail));
  18.     skb->truesize = size + sizeof(struct sk_buff);
  19.     atomic_set(&skb->users, 1);
  20.     skb->head = data;
  21.     skb->data = data;
  22.     skb_reset_tail_pointer(skb);
  23.     skb->end = skb->tail + size;
  24.     kmemcheck_annotate_bitfield(skb, flags1);
  25.     kmemcheck_annotate_bitfield(skb, flags2);
  26. #ifdef NET_SKBUFF_DATA_USES_OFFSET
  27.     skb->mac_header = ~0U;
  28. #endif

  29.     /* make sure we initialize shinfo sequentially */
  30.     shinfo = skb_shinfo(skb);
  31.     memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
  32.     atomic_set(&shinfo->dataref, 1);

  33.     if (fclone) {
  34.         /* 如果是fclone cache的话,那么skb的下一个buf,也将被分配*/
  35.         struct sk_buff *child = skb + 1;
  36.         atomic_t *fclone_ref = (atomic_t *) (child + 1);

  37.         kmemcheck_annotate_bitfield(child, flags1);
  38.         kmemcheck_annotate_bitfield(child, flags2);
  39.         skb->fclone = SKB_FCLONE_ORIG;
  40.         atomic_set(fclone_ref, 1);

  41.         child->fclone = SKB_FCLONE_UNAVAILABLE;
  42.     }
  43. out:
  44.     return skb;
  45. nodata:
  46.     kmem_cache_free(cache, skb);
  47.     skb = NULL;
  48.     goto out;
  49. }
这里有两个cache,skbuff_fclone_cache和skbuff_head_cache。它们两个的区别是前者是每两个skb为一组。当从skbuff_fclone_cache分配skb时,会两个连续的skb一起分配,但是释放的时候可以分别释放。也就是说当调用者知道需要两个skb时,如后面的操作很可能使用skb_clone时,那么从skbuff_fclone_cache上分配skb会更高效一些。

从skb的这个函数上看,可以从中看出linux在内存方面对效率的追求。在我们平时的工作中,也可以采用类似的内存池机制来提高效率和管理内存。
阅读(485) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~