From 7eaf0de9eb5d335d741545bc1beb2753f7ecae1b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 13 Feb 2006 16:06:10 -0800 Subject: [PATCH] --- yaml --- r: 20259 b: refs/heads/master c: b4d9eda028e8becbb5057b554e63eea12e496a88 h: refs/heads/master i: 20257: 4050e8a97a2d36e4a65aabc9f53775c520e07547 20255: 7a7eda3e5e0350c9ea83373a2e1576f409ade8d0 v: v3 --- [refs] | 2 +- trunk/net/core/datagram.c | 81 +++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/[refs] b/[refs] index 14d51a4e2694..40762828bc76 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 00de651d14baabc5c1d2f32c49d9a984d8891c8e +refs/heads/master: b4d9eda028e8becbb5057b554e63eea12e496a88 diff --git a/trunk/net/core/datagram.c b/trunk/net/core/datagram.c index f8d322e1ea92..b8ce6bf81188 100644 --- a/trunk/net/core/datagram.c +++ b/trunk/net/core/datagram.c @@ -247,49 +247,74 @@ EXPORT_SYMBOL(skb_kill_datagram); int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec *to, int len) { - int i, err, fraglen, end = 0; - struct sk_buff *next = skb_shinfo(skb)->frag_list; + int start = skb_headlen(skb); + int i, copy = start - offset; - if (!len) - return 0; + /* Copy header. */ + if (copy > 0) { + if (copy > len) + copy = len; + if (memcpy_toiovec(to, skb->data + offset, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + } -next_skb: - fraglen = skb_headlen(skb); - i = -1; + /* Copy paged appendix. Hmm... why does this look so complicated? */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + int end; - while (1) { - int start = end; + BUG_TRAP(start <= offset + len); - if ((end += fraglen) > offset) { - int copy = end - offset, o = offset - start; + end = start + skb_shinfo(skb)->frags[i].size; + if ((copy = end - offset) > 0) { + int err; + u8 *vaddr; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = frag->page; if (copy > len) copy = len; - if (i == -1) - err = memcpy_toiovec(to, skb->data + o, copy); - else { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - struct page *page = frag->page; - void *p = kmap(page) + frag->page_offset + o; - err = memcpy_toiovec(to, p, copy); - kunmap(page); - } + vaddr = kmap(page); + err = memcpy_toiovec(to, vaddr + frag->page_offset + + offset - start, copy); + kunmap(page); if (err) goto fault; if (!(len -= copy)) return 0; offset += copy; } - if (++i >= skb_shinfo(skb)->nr_frags) - break; - fraglen = skb_shinfo(skb)->frags[i].size; + start = end; } - if (next) { - skb = next; - BUG_ON(skb_shinfo(skb)->frag_list); - next = skb->next; - goto next_skb; + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list = skb_shinfo(skb)->frag_list; + + for (; list; list = list->next) { + int end; + + BUG_TRAP(start <= offset + len); + + end = start + list->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_copy_datagram_iovec(list, + offset - start, + to, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + } + start = end; + } } + if (!len) + return 0; + fault: return -EFAULT; }