Chinaunix首页 | 论坛 | 博客
  • 博客访问: 86386
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 210
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-05 15:27
文章分类

全部博文(15)

文章存档

2014年(15)

我的朋友

分类: LINUX

2014-04-07 21:40:38

struct iovec数据结构在网络和IO的很多地方都使用,数据结构比较简单:
  1. struct iovec
  2. {
  3.     void __user *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
  4.     __kernel_size_t iov_len; /* Must be size_t (1003.1g) */
  5. };
1:skb_copy_datagram_iovec,该函数在收包流程udp_recvmsg中就有用到,作用是把skb相关的数据拷贝到iovec的数据结构中,传给用户,调该函数的时候L4底下的协议已经处理完了,data指向L4的头开始处:
  1. int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, //offset为L4的头大小
  2.                 struct iovec *to, int len)  //len为min{用户传入的值大小,skb带负载的大小}
  3. {
  4.     int start = skb_headlen(skb);//线性区大小
  5.     int i, copy = start - offset;
  6.     struct sk_buff *frag_iter;

  7.     trace_skb_copy_datagram_iovec(skb, len); //debugfs中有该函数的trace点

  8.     /* Copy header. */
  9.     if (copy > 0) {         //1:拷贝线性区
  10.         if (copy > len)
  11.             copy = len;
  12.         if (memcpy_toiovec(to, skb->data + offset, copy))  //copy_to_user
  13.             goto fault;
  14.         if ((len -= copy) == 0)
  15.             return 0;
  16.         offset += copy;
  17.     }

  18.     /* Copy paged appendix. Hmm... why does this look so complicated? */
  19.     for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {  //2:拷贝SG区,该段代码作用很简单,但是逻辑有点复杂,需要考虑L4头的具体位置
  20.         int end;

  21.         WARN_ON(start > offset + len);

  22.         end = start + skb_shinfo(skb)->frags[i].size;
  23.         if ((copy = end - offset) > 0)
  24.             int err;
  25.             u8 *vaddr;
  26.             skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
  27.             struct page *page = frag->page;

  28.             if (copy > len)
  29.                 copy = len;
  30.             vaddr = kmap(page);
  31.             err = memcpy_toiovec(to, vaddr + frag->page_offset
  32.                          offset - start, copy); //如果L4在线性区的话,不需要这么复杂,但是如果L4在当前区域的话,需要略过头
  33.             kunmap(page);
  34.             if (err)
  35.                 goto fault;
  36.             if (!(len -= copy))
  37.                 return 0;
  38.             offset += copy;
  39.         }
  40.         start = end;
  41.     }

  42.     skb_walk_frags(skb, frag_iter) {  //3:拷贝fraglist,如ip defrag后
  43.         int end;

  44.         WARN_ON(start > offset + len);

  45.         end = start + frag_iter->len;
  46.         if ((copy = end - offset) > 0) {
  47.             if (copy > len)
  48.                 copy = len;
  49.             if (skb_copy_datagram_iovec(frag_iter,  //递归调用,最深不会调用2次
  50.                             offset - start,
  51.                             to, copy))
  52.                 goto fault;
  53.             if ((len -= copy) == 0)
  54.                 return 0;
  55.             offset += copy;
  56.         }
  57.         start = end;
  58.     }
  59.     if (!len)
  60.         return 0;

  61. fault:
  62.     return -EFAULT;
  63. }

阅读(7846) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~