|
@@ -2686,48 +2686,37 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
|
|
|
int len, int odd, struct sk_buff *skb),
|
|
|
void *from, int length)
|
|
|
{
|
|
|
- int frg_cnt = 0;
|
|
|
- skb_frag_t *frag = NULL;
|
|
|
- struct page *page = NULL;
|
|
|
- int copy, left;
|
|
|
+ int frg_cnt = skb_shinfo(skb)->nr_frags;
|
|
|
+ int copy;
|
|
|
int offset = 0;
|
|
|
int ret;
|
|
|
+ struct page_frag *pfrag = ¤t->task_frag;
|
|
|
|
|
|
do {
|
|
|
/* Return error if we don't have space for new frag */
|
|
|
- frg_cnt = skb_shinfo(skb)->nr_frags;
|
|
|
if (frg_cnt >= MAX_SKB_FRAGS)
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- /* allocate a new page for next frag */
|
|
|
- page = alloc_pages(sk->sk_allocation, 0);
|
|
|
+ return -EMSGSIZE;
|
|
|
|
|
|
- /* If alloc_page fails just return failure and caller will
|
|
|
- * free previous allocated pages by doing kfree_skb()
|
|
|
- */
|
|
|
- if (page == NULL)
|
|
|
+ if (!sk_page_frag_refill(sk, pfrag))
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- /* initialize the next frag */
|
|
|
- skb_fill_page_desc(skb, frg_cnt, page, 0, 0);
|
|
|
- skb->truesize += PAGE_SIZE;
|
|
|
- atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
|
|
|
-
|
|
|
- /* get the new initialized frag */
|
|
|
- frg_cnt = skb_shinfo(skb)->nr_frags;
|
|
|
- frag = &skb_shinfo(skb)->frags[frg_cnt - 1];
|
|
|
-
|
|
|
/* copy the user data to page */
|
|
|
- left = PAGE_SIZE - frag->page_offset;
|
|
|
- copy = (length > left)? left : length;
|
|
|
+ copy = min_t(int, length, pfrag->size - pfrag->offset);
|
|
|
|
|
|
- ret = getfrag(from, skb_frag_address(frag) + skb_frag_size(frag),
|
|
|
- offset, copy, 0, skb);
|
|
|
+ ret = getfrag(from, page_address(pfrag->page) + pfrag->offset,
|
|
|
+ offset, copy, 0, skb);
|
|
|
if (ret < 0)
|
|
|
return -EFAULT;
|
|
|
|
|
|
/* copy was successful so update the size parameters */
|
|
|
- skb_frag_size_add(frag, copy);
|
|
|
+ skb_fill_page_desc(skb, frg_cnt, pfrag->page, pfrag->offset,
|
|
|
+ copy);
|
|
|
+ frg_cnt++;
|
|
|
+ pfrag->offset += copy;
|
|
|
+ get_page(pfrag->page);
|
|
|
+
|
|
|
+ skb->truesize += copy;
|
|
|
+ atomic_add(copy, &sk->sk_wmem_alloc);
|
|
|
skb->len += copy;
|
|
|
skb->data_len += copy;
|
|
|
offset += copy;
|