[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>

authored by Daniel Phillips and committed by David S. Miller bc8dfcb9 95001ee9

+26 -55
+26 -55
net/core/datagram.c
··· 211 211 int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, 212 212 struct iovec *to, int len) 213 213 { 214 - int start = skb_headlen(skb); 215 - int i, copy = start - offset; 214 + int i, err, fraglen, end = 0; 215 + struct sk_buff *next = skb_shinfo(skb)->frag_list; 216 + next_skb: 217 + fraglen = skb_headlen(skb); 218 + i = -1; 216 219 217 - /* Copy header. */ 218 - if (copy > 0) { 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 - } 220 + while (1) { 221 + int start = end; 227 222 228 - /* Copy paged appendix. Hmm... why does this look so complicated? */ 229 - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 230 - int end; 231 - 232 - BUG_TRAP(start <= offset + len); 233 - 234 - end = start + skb_shinfo(skb)->frags[i].size; 235 - if ((copy = end - offset) > 0) { 236 - int err; 237 - u8 *vaddr; 238 - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 239 - struct page *page = frag->page; 223 + if ((end += fraglen) > offset) { 224 + int copy = end - offset, o = offset - start; 240 225 241 226 if (copy > len) 242 227 copy = len; 243 - vaddr = kmap(page); 244 - err = memcpy_toiovec(to, vaddr + frag->page_offset + 245 - offset - start, copy); 246 - kunmap(page); 228 + if (i == -1) 229 + err = memcpy_toiovec(to, skb->data + o, copy); 230 + else { 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 237 if (err) 248 238 goto fault; 249 239 if (!(len -= copy)) 250 240 return 0; 251 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 - 256 - if (skb_shinfo(skb)->frag_list) { 257 - struct sk_buff *list = skb_shinfo(skb)->frag_list; 258 - 259 - for (; list; list = list->next) { 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 - } 247 + if (next) { 248 + skb = next; 249 + BUG_ON(skb_shinfo(skb)->frag_list); 250 + next = skb->next; 251 + goto next_skb; 278 252 } 279 - if (!len) 280 - return 0; 281 - 282 253 fault: 283 254 return -EFAULT; 284 255 }