- if (copy > length)
-
copy = length;
-
-
if (!(rt->dst.dev->features&NETIF_F_SG)) {
- /* 如果网卡不支持Scatter/gather特性,直接拷贝数据 */
-
unsigned int off;
-
-
off = skb->len;
-
if (getfrag(from, skb_put(skb, copy),
-
offset, copy, off, skb) < 0) {
-
__skb_trim(skb, off);
-
err = -EFAULT;
-
goto error;
-
}
-
} else {
- /* 如果支持Scatter/gather特性 */
/* 得到已储存的buffer个数 */
-
int i = skb_shinfo(skb)->nr_frags;
-
skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
- /* 得到物理页面的地址 */
-
struct page *page = sk->sk_sndmsg_page;
-
int off = sk->sk_sndmsg_off;
-
unsigned int left;
-
-
if (page && (left = PAGE_SIZE - off) > 0) {
- /* 该页还有空余空间,可以填充一部分数据 */
/* 如果要拷贝的长度大于剩余空间,调整拷贝的长度 */
-
if (copy >= left)
-
copy = left;
-
if (page != frag->page) {
- /* 此次数据与sock上次缓冲数据不是位于同一物理页面 */
-
if (i == MAX_SKB_FRAGS) {
- /* 超过了缓存数据最大个数 */
-
err = -EMSGSIZE;
-
goto error;
-
}
-
get_page(page);
- /* 将数据填充到物理页 */
-
skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
-
frag = &skb_shinfo(skb)->frags[i];
-
}
-
} else if (i < MAX_SKB_FRAGS) {
- /* 将拷贝长度调整为物理页最大值 */
-
if (copy > PAGE_SIZE)
-
copy = PAGE_SIZE;
- /* 分配一个新的物理页 */
-
page = alloc_pages(sk->sk_allocation, 0);
-
if (page == NULL) {
-
err = -ENOMEM;
-
goto error;
-
}
- /* 保存物理页地址 */
-
sk->sk_sndmsg_page = page;
-
sk->sk_sndmsg_off = 0;
/* 填充物理页 */
-
skb_fill_page_desc(skb, i, page, 0, 0);
-
frag = &skb_shinfo(skb)->frags[i];
-
} else {
-
err = -EMSGSIZE;
-
goto error;
-
}
/* 调用getfrag填充数据 */
-
if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) {
-
err = -EFAULT;
-
goto error;
-
}
/* 调整各个偏移以及长度 */
-
sk->sk_sndmsg_off += copy;
-
frag->size += copy;
-
skb->len += copy;
-
skb->data_len += copy;
-
skb->truesize += copy;
-
atomic_add(copy, &sk->sk_wmem_alloc);
-
}
- /* 继续下一个 */
-
offset += copy;
-
length -= copy;
-
}
-
-
return 0;
-
-
error:
-
inet->cork.length -= length;
-
IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS);
-
return err;