aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorZoltan Kiss <zoltan.kiss@citrix.com>2014-03-26 18:37:45 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-27 15:29:38 -0400
commit36d5fe6a000790f56039afe26834265db0a3ad4c (patch)
tree391de83f18ede9ca651ed347112ce4400e4645d5 /net/core
parentfc0d48b8fb449ca007b2057328abf736cb516168 (diff)
core, nfqueue, openvswitch: Orphan frags in skb_zerocopy and handle errors
skb_zerocopy can copy elements of the frags array between skbs, but it doesn't orphan them. Also, it doesn't handle errors, so this patch takes care of that as well, and modify the callers accordingly. skb_tx_error() is also added to the callers so they will signal the failed delivery towards the creator of the skb. Signed-off-by: Zoltan Kiss <zoltan.kiss@citrix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 869c7afe3b07..97e5a2c3d947 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2127,25 +2127,31 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
2127 * 2127 *
2128 * The `hlen` as calculated by skb_zerocopy_headlen() specifies the 2128 * The `hlen` as calculated by skb_zerocopy_headlen() specifies the
2129 * headroom in the `to` buffer. 2129 * headroom in the `to` buffer.
2130 *
2131 * Return value:
2132 * 0: everything is OK
2133 * -ENOMEM: couldn't orphan frags of @from due to lack of memory
2134 * -EFAULT: skb_copy_bits() found some problem with skb geometry
2130 */ 2135 */
2131void 2136int
2132skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) 2137skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
2133{ 2138{
2134 int i, j = 0; 2139 int i, j = 0;
2135 int plen = 0; /* length of skb->head fragment */ 2140 int plen = 0; /* length of skb->head fragment */
2141 int ret;
2136 struct page *page; 2142 struct page *page;
2137 unsigned int offset; 2143 unsigned int offset;
2138 2144
2139 BUG_ON(!from->head_frag && !hlen); 2145 BUG_ON(!from->head_frag && !hlen);
2140 2146
2141 /* dont bother with small payloads */ 2147 /* dont bother with small payloads */
2142 if (len <= skb_tailroom(to)) { 2148 if (len <= skb_tailroom(to))
2143 skb_copy_bits(from, 0, skb_put(to, len), len); 2149 return skb_copy_bits(from, 0, skb_put(to, len), len);
2144 return;
2145 }
2146 2150
2147 if (hlen) { 2151 if (hlen) {
2148 skb_copy_bits(from, 0, skb_put(to, hlen), hlen); 2152 ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
2153 if (unlikely(ret))
2154 return ret;
2149 len -= hlen; 2155 len -= hlen;
2150 } else { 2156 } else {
2151 plen = min_t(int, skb_headlen(from), len); 2157 plen = min_t(int, skb_headlen(from), len);
@@ -2163,6 +2169,11 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
2163 to->len += len + plen; 2169 to->len += len + plen;
2164 to->data_len += len + plen; 2170 to->data_len += len + plen;
2165 2171
2172 if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
2173 skb_tx_error(from);
2174 return -ENOMEM;
2175 }
2176
2166 for (i = 0; i < skb_shinfo(from)->nr_frags; i++) { 2177 for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
2167 if (!len) 2178 if (!len)
2168 break; 2179 break;
@@ -2173,6 +2184,8 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
2173 j++; 2184 j++;
2174 } 2185 }
2175 skb_shinfo(to)->nr_frags = j; 2186 skb_shinfo(to)->nr_frags = j;
2187
2188 return 0;
2176} 2189}
2177EXPORT_SYMBOL_GPL(skb_zerocopy); 2190EXPORT_SYMBOL_GPL(skb_zerocopy);
2178 2191