- 论坛徽章:
- 15
|
jiufei19 发表于 2014-03-13 21:02
回复 8# humjb_1983
引用专家的注释代码,兄弟可以理解下,个人理解,tcp_sendmsg中填充数据时,会先填充skb->data的空间,填满后才会填充frags(可能需要分配新页)。- /* Where to copy to? */
- if (skb_tailroom(skb) > 0) {/* skb线性存储区底部还有空间 */
- /* We have some space in skb head. Superb! */
- if (copy > skb_tailroom(skb))/* 本次只复制skb存储区底部剩余空间大小的数据量 */
- copy = skb_tailroom(skb);
- /* 从用户空间复制指定长度的数据到skb中,如果失败,则退出 */
- if ((err = skb_add_data(skb, from, copy)) != 0)
- goto do_fault;
- } else {/* 线性存储区底部已经没有空间了,复制到分散/聚集存储区中 */
- int merge = 0;/* 是否在页中添加数据 */
- int i = skb_shinfo(skb)->nr_frags;/* 分散/聚集片断数 */
- struct page *page = TCP_PAGE(sk);/* 分片页页 */
- int off = TCP_OFF(sk);/* 分片内的偏移 */
- if (skb_can_coalesce(skb, i, page, off) &&
- off != PAGE_SIZE) {/* 当前分片还能添加数据 */
- /* We can extend the last page
- * fragment. */
- merge = 1;
- } else if (i == MAX_SKB_FRAGS ||/* 目前skb中的页不能添加数据,这里判断是否能再分配页 */
- (!i &&
- !(sk->sk_route_caps & NETIF_F_SG))) {/* 网卡不支持S/G,不能分片 */
- /* Need to add new fragment and cannot
- * do this because interface is non-SG,
- * or because all the page slots are
- * busy. */
- tcp_mark_push(tp, skb);/* SKB可以提交了 */
- goto new_segment;/* 重新分配skb */
- } else if (page) {/* 分页数量未达到上限,判断当前页是否还有空间 */
- /* If page is cached, align
- * offset to L1 cache boundary
- */
- off = (off + L1_CACHE_BYTES - 1) &
- ~(L1_CACHE_BYTES - 1);
- if (off == PAGE_SIZE) {/* 最后一个分页数据已经满,需要分配新页 */
- put_page(page);
- TCP_PAGE(sk) = page = NULL;
- }
- }
- if (!page) {/* 需要分配新页 */
- /* Allocate new cache page. */
- if (!(page = sk_stream_alloc_page(sk)))/* 分配新页,如果内存不足则等待内存 */
- goto wait_for_memory;
- off = 0;
- }
- if (copy > PAGE_SIZE - off)/* 待复制的数据不能大于页中剩余空间 */
- copy = PAGE_SIZE - off;
- /* Time to copy data. We are close to
- * the end! */
- err = skb_copy_to_page(sk, from, skb, page,
- off, copy);/* 从用户态复制数据到页中 */
- if (err) {/* 复制失败了 */
- /* If this page was new, give it to the
- * socket so it does not get leaked.
- */
- if (!TCP_PAGE(sk)) {/* 如果是新分配的页,则将页记录到skb中,供今后使用 */
- TCP_PAGE(sk) = page;
- TCP_OFF(sk) = 0;
- }
- goto do_error;
- }
- /* Update the skb. */
- /* 更新skb的分段信息 */
- if (merge) {/* 在最后一个页中追加数据 */
- skb_shinfo(skb)->frags[i - 1].size +=
- copy;/* 更新最后一页的数据长度 */
- } else {/* 新分配的页 */
- /* 更新skb中分片信息 */
- skb_fill_page_desc(skb, i, page, off, copy);
- if (TCP_PAGE(sk)) {
- get_page(page);
- } else if (off + copy < PAGE_SIZE) {
- get_page(page);
- TCP_PAGE(sk) = page;
- }
- }
- /* 更新页内偏移 */
- TCP_OFF(sk) = off + copy;
- }
复制代码 |
|