ipsec: ipcomp - Decompress into frags if necessary

When decompressing extremely large packets allocating them through
kmalloc is prone to failure. Therefore it's better to use page
frags instead.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
7d7e5a60 6fccab67

+42 -6
+42 -6
net/xfrm/xfrm_ipcomp.c
··· 17 18 #include <linux/crypto.h> 19 #include <linux/err.h> 20 #include <linux/list.h> 21 #include <linux/module.h> 22 #include <linux/mutex.h> ··· 50 u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); 51 struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); 52 int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen); 53 54 if (err) 55 goto out; ··· 60 goto out; 61 } 62 63 - err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC); 64 - if (err) 65 - goto out; 66 67 - skb->truesize += dlen - plen; 68 - __skb_put(skb, dlen - plen); 69 - skb_copy_to_linear_data(skb, scratch, dlen); 70 out: 71 put_cpu(); 72 return err;
··· 17 18 #include <linux/crypto.h> 19 #include <linux/err.h> 20 + #include <linux/gfp.h> 21 #include <linux/list.h> 22 #include <linux/module.h> 23 #include <linux/mutex.h> ··· 49 u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); 50 struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); 51 int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen); 52 + int len; 53 54 if (err) 55 goto out; ··· 58 goto out; 59 } 60 61 + len = dlen - plen; 62 + if (len > skb_tailroom(skb)) 63 + len = skb_tailroom(skb); 64 65 + skb->truesize += len; 66 + __skb_put(skb, len); 67 + 68 + len += plen; 69 + skb_copy_to_linear_data(skb, scratch, len); 70 + 71 + while ((scratch += len, dlen -= len) > 0) { 72 + skb_frag_t *frag; 73 + 74 + err = -EMSGSIZE; 75 + if (WARN_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) 76 + goto out; 77 + 78 + frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; 79 + frag->page = alloc_page(GFP_ATOMIC); 80 + 81 + err = -ENOMEM; 82 + if (!frag->page) 83 + goto out; 84 + 85 + len = PAGE_SIZE; 86 + if (dlen < len) 87 + len = dlen; 88 + 89 + memcpy(page_address(frag->page), scratch, len); 90 + 91 + frag->page_offset = 0; 92 + frag->size = len; 93 + skb->truesize += len; 94 + skb->data_len += len; 95 + skb->len += len; 96 + 97 + skb_shinfo(skb)->nr_frags++; 98 + } 99 + 100 + err = 0; 101 + 102 out: 103 put_cpu(); 104 return err;