diff options
| author | Daniel Phillips <phillips@istop.com> | 2005-09-27 18:22:35 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2005-09-27 18:22:35 -0400 |
| commit | bc8dfcb93970ad7139c976356bfc99d7e251deaf (patch) | |
| tree | afcd38d0fda2f35edf11535d56fc9c54acab4808 | |
| parent | 95001ee9256df846e374f116c92ca8e0beec1527 (diff) | |
[NET]: Use non-recursive algorithm in skb_copy_datagram_iovec()
Use iteration instead of recursion. Fraglists within fraglists
should never occur, so we BUG check this.
Signed-off-by: Daniel Phillips <phillips@istop.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/core/datagram.c | 81 |
1 files changed, 26 insertions, 55 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c index da9bf71421a7..81987df536eb 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
| @@ -211,74 +211,45 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb) | |||
| 211 | int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, | 211 | int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, |
| 212 | struct iovec *to, int len) | 212 | struct iovec *to, int len) |
| 213 | { | 213 | { |
| 214 | int start = skb_headlen(skb); | 214 | int i, err, fraglen, end = 0; |
| 215 | int i, copy = start - offset; | 215 | struct sk_buff *next = skb_shinfo(skb)->frag_list; |
| 216 | 216 | next_skb: | |
| 217 | /* Copy header. */ | 217 | fraglen = skb_headlen(skb); |
| 218 | if (copy > 0) { | 218 | i = -1; |
| 219 | if (copy > len) | ||
| 220 | copy = len; | ||
| 221 | if (memcpy_toiovec(to, skb->data + offset, copy)) | ||
| 222 | goto fault; | ||
| 223 | if ((len -= copy) == 0) | ||
| 224 | return 0; | ||
| 225 | offset += copy; | ||
| 226 | } | ||
| 227 | 219 | ||
| 228 | /* Copy paged appendix. Hmm... why does this look so complicated? */ | 220 | while (1) { |
| 229 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 221 | int start = end; |
| 230 | int end; | ||
| 231 | |||
| 232 | BUG_TRAP(start <= offset + len); | ||
| 233 | 222 | ||
| 234 | end = start + skb_shinfo(skb)->frags[i].size; | 223 | if ((end += fraglen) > offset) { |
| 235 | if ((copy = end - offset) > 0) { | 224 | int copy = end - offset, o = offset - start; |
| 236 | int err; | ||
| 237 | u8 *vaddr; | ||
| 238 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||
| 239 | struct page *page = frag->page; | ||
| 240 | 225 | ||
| 241 | if (copy > len) | 226 | if (copy > len) |
| 242 | copy = len; | 227 | copy = len; |
| 243 | vaddr = kmap(page); | 228 | if (i == -1) |
| 244 | err = memcpy_toiovec(to, vaddr + frag->page_offset + | 229 | err = memcpy_toiovec(to, skb->data + o, copy); |
| 245 | offset - start, copy); | 230 | else { |
| 246 | kunmap(page); | 231 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
| 232 | struct page *page = frag->page; | ||
| 233 | void *p = kmap(page) + frag->page_offset + o; | ||
| 234 | err = memcpy_toiovec(to, p, copy); | ||
| 235 | kunmap(page); | ||
| 236 | } | ||
| 247 | if (err) | 237 | if (err) |
| 248 | goto fault; | 238 | goto fault; |
| 249 | if (!(len -= copy)) | 239 | if (!(len -= copy)) |
| 250 | return 0; | 240 | return 0; |
| 251 | offset += copy; | 241 | offset += copy; |
| 252 | } | 242 | } |
| 253 | start = end; | 243 | if (++i >= skb_shinfo(skb)->nr_frags) |
| 244 | break; | ||
| 245 | fraglen = skb_shinfo(skb)->frags[i].size; | ||
| 254 | } | 246 | } |
| 255 | 247 | if (next) { | |
| 256 | if (skb_shinfo(skb)->frag_list) { | 248 | skb = next; |
| 257 | struct sk_buff *list = skb_shinfo(skb)->frag_list; | 249 | BUG_ON(skb_shinfo(skb)->frag_list); |
| 258 | 250 | next = skb->next; | |
| 259 | for (; list; list = list->next) { | 251 | goto next_skb; |
| 260 | int end; | ||
| 261 | |||
| 262 | BUG_TRAP(start <= offset + len); | ||
| 263 | |||
| 264 | end = start + list->len; | ||
| 265 | if ((copy = end - offset) > 0) { | ||
| 266 | if (copy > len) | ||
| 267 | copy = len; | ||
| 268 | if (skb_copy_datagram_iovec(list, | ||
| 269 | offset - start, | ||
| 270 | to, copy)) | ||
| 271 | goto fault; | ||
| 272 | if ((len -= copy) == 0) | ||
| 273 | return 0; | ||
| 274 | offset += copy; | ||
| 275 | } | ||
| 276 | start = end; | ||
| 277 | } | ||
| 278 | } | 252 | } |
| 279 | if (!len) | ||
| 280 | return 0; | ||
| 281 | |||
| 282 | fault: | 253 | fault: |
| 283 | return -EFAULT; | 254 | return -EFAULT; |
| 284 | } | 255 | } |
