aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/macvtap.c4
-rw-r--r--drivers/net/tun.c13
-rw-r--r--drivers/net/virtio_net.c13
-rw-r--r--include/linux/skbuff.h17
-rw-r--r--net/core/skbuff.c5
-rw-r--r--net/ipv4/af_inet.c1
-rw-r--r--net/ipv4/ip_output.c1
-rw-r--r--net/ipv4/tcp.c4
-rw-r--r--net/ipv4/tcp_input.c4
-rw-r--r--net/ipv4/tcp_output.c4
-rw-r--r--net/ipv6/ip6_offload.c1
11 files changed, 29 insertions, 38 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index b181dfb3d6d6..97243011d319 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -543,7 +543,6 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
543 skb->data_len += len; 543 skb->data_len += len;
544 skb->len += len; 544 skb->len += len;
545 skb->truesize += truesize; 545 skb->truesize += truesize;
546 skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG;
547 atomic_add(truesize, &skb->sk->sk_wmem_alloc); 546 atomic_add(truesize, &skb->sk->sk_wmem_alloc);
548 while (len) { 547 while (len) {
549 int off = base & ~PAGE_MASK; 548 int off = base & ~PAGE_MASK;
@@ -599,7 +598,7 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
599 598
600 if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { 599 if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
601 skb_shinfo(skb)->gso_size = vnet_hdr->gso_size; 600 skb_shinfo(skb)->gso_size = vnet_hdr->gso_size;
602 skb_shinfo(skb)->gso_type |= gso_type; 601 skb_shinfo(skb)->gso_type = gso_type;
603 602
604 /* Header must be checked, and gso_segs computed. */ 603 /* Header must be checked, and gso_segs computed. */
605 skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; 604 skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
@@ -743,6 +742,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
743 if (zerocopy) { 742 if (zerocopy) {
744 skb_shinfo(skb)->destructor_arg = m->msg_control; 743 skb_shinfo(skb)->destructor_arg = m->msg_control;
745 skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; 744 skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
745 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
746 } 746 }
747 if (vlan) 747 if (vlan)
748 macvlan_start_xmit(skb, vlan->dev); 748 macvlan_start_xmit(skb, vlan->dev);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index b1038c0e2240..b6f45c5d84d5 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1019,7 +1019,6 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
1019 skb->data_len += len; 1019 skb->data_len += len;
1020 skb->len += len; 1020 skb->len += len;
1021 skb->truesize += truesize; 1021 skb->truesize += truesize;
1022 skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG;
1023 atomic_add(truesize, &skb->sk->sk_wmem_alloc); 1022 atomic_add(truesize, &skb->sk->sk_wmem_alloc);
1024 while (len) { 1023 while (len) {
1025 int off = base & ~PAGE_MASK; 1024 int off = base & ~PAGE_MASK;
@@ -1165,18 +1164,16 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
1165 } 1164 }
1166 1165
1167 if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { 1166 if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
1168 unsigned short gso_type = 0;
1169
1170 pr_debug("GSO!\n"); 1167 pr_debug("GSO!\n");
1171 switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { 1168 switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
1172 case VIRTIO_NET_HDR_GSO_TCPV4: 1169 case VIRTIO_NET_HDR_GSO_TCPV4:
1173 gso_type = SKB_GSO_TCPV4; 1170 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
1174 break; 1171 break;
1175 case VIRTIO_NET_HDR_GSO_TCPV6: 1172 case VIRTIO_NET_HDR_GSO_TCPV6:
1176 gso_type = SKB_GSO_TCPV6; 1173 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
1177 break; 1174 break;
1178 case VIRTIO_NET_HDR_GSO_UDP: 1175 case VIRTIO_NET_HDR_GSO_UDP:
1179 gso_type = SKB_GSO_UDP; 1176 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
1180 break; 1177 break;
1181 default: 1178 default:
1182 tun->dev->stats.rx_frame_errors++; 1179 tun->dev->stats.rx_frame_errors++;
@@ -1185,10 +1182,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
1185 } 1182 }
1186 1183
1187 if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN) 1184 if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN)
1188 gso_type |= SKB_GSO_TCP_ECN; 1185 skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
1189 1186
1190 skb_shinfo(skb)->gso_size = gso.gso_size; 1187 skb_shinfo(skb)->gso_size = gso.gso_size;
1191 skb_shinfo(skb)->gso_type |= gso_type;
1192 if (skb_shinfo(skb)->gso_size == 0) { 1188 if (skb_shinfo(skb)->gso_size == 0) {
1193 tun->dev->stats.rx_frame_errors++; 1189 tun->dev->stats.rx_frame_errors++;
1194 kfree_skb(skb); 1190 kfree_skb(skb);
@@ -1204,6 +1200,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
1204 if (zerocopy) { 1200 if (zerocopy) {
1205 skb_shinfo(skb)->destructor_arg = msg_control; 1201 skb_shinfo(skb)->destructor_arg = msg_control;
1206 skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; 1202 skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
1203 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
1207 } 1204 }
1208 1205
1209 skb_reset_network_header(skb); 1206 skb_reset_network_header(skb);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 381a2d8d8a81..192c91c8e799 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -227,7 +227,7 @@ static void set_skb_frag(struct sk_buff *skb, struct page *page,
227 skb->len += size; 227 skb->len += size;
228 skb->truesize += PAGE_SIZE; 228 skb->truesize += PAGE_SIZE;
229 skb_shinfo(skb)->nr_frags++; 229 skb_shinfo(skb)->nr_frags++;
230 skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG; 230 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
231 *len -= size; 231 *len -= size;
232} 232}
233 233
@@ -387,18 +387,16 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
387 ntohs(skb->protocol), skb->len, skb->pkt_type); 387 ntohs(skb->protocol), skb->len, skb->pkt_type);
388 388
389 if (hdr->hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) { 389 if (hdr->hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
390 unsigned short gso_type = 0;
391
392 pr_debug("GSO!\n"); 390 pr_debug("GSO!\n");
393 switch (hdr->hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { 391 switch (hdr->hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
394 case VIRTIO_NET_HDR_GSO_TCPV4: 392 case VIRTIO_NET_HDR_GSO_TCPV4:
395 gso_type = SKB_GSO_TCPV4; 393 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
396 break; 394 break;
397 case VIRTIO_NET_HDR_GSO_UDP: 395 case VIRTIO_NET_HDR_GSO_UDP:
398 gso_type = SKB_GSO_UDP; 396 skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
399 break; 397 break;
400 case VIRTIO_NET_HDR_GSO_TCPV6: 398 case VIRTIO_NET_HDR_GSO_TCPV6:
401 gso_type = SKB_GSO_TCPV6; 399 skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
402 break; 400 break;
403 default: 401 default:
404 net_warn_ratelimited("%s: bad gso type %u.\n", 402 net_warn_ratelimited("%s: bad gso type %u.\n",
@@ -407,7 +405,7 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
407 } 405 }
408 406
409 if (hdr->hdr.gso_type & VIRTIO_NET_HDR_GSO_ECN) 407 if (hdr->hdr.gso_type & VIRTIO_NET_HDR_GSO_ECN)
410 gso_type |= SKB_GSO_TCP_ECN; 408 skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
411 409
412 skb_shinfo(skb)->gso_size = hdr->hdr.gso_size; 410 skb_shinfo(skb)->gso_size = hdr->hdr.gso_size;
413 if (skb_shinfo(skb)->gso_size == 0) { 411 if (skb_shinfo(skb)->gso_size == 0) {
@@ -415,7 +413,6 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
415 goto frame_err; 413 goto frame_err;
416 } 414 }
417 415
418 skb_shinfo(skb)->gso_type |= gso_type;
419 /* Header must be checked, and gso_segs computed. */ 416 /* Header must be checked, and gso_segs computed. */
420 skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; 417 skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
421 skb_shinfo(skb)->gso_segs = 0; 418 skb_shinfo(skb)->gso_segs = 0;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index d7573c37a51d..9da99520ccd5 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -230,6 +230,13 @@ enum {
230 230
231 /* generate wifi status information (where possible) */ 231 /* generate wifi status information (where possible) */
232 SKBTX_WIFI_STATUS = 1 << 4, 232 SKBTX_WIFI_STATUS = 1 << 4,
233
234 /* This indicates at least one fragment might be overwritten
235 * (as in vmsplice(), sendfile() ...)
236 * If we need to compute a TX checksum, we'll need to copy
237 * all frags to avoid possible bad checksum
238 */
239 SKBTX_SHARED_FRAG = 1 << 5,
233}; 240};
234 241
235/* 242/*
@@ -307,13 +314,6 @@ enum {
307 SKB_GSO_TCPV6 = 1 << 4, 314 SKB_GSO_TCPV6 = 1 << 4,
308 315
309 SKB_GSO_FCOE = 1 << 5, 316 SKB_GSO_FCOE = 1 << 5,
310
311 /* This indicates at least one fragment might be overwritten
312 * (as in vmsplice(), sendfile() ...)
313 * If we need to compute a TX checksum, we'll need to copy
314 * all frags to avoid possible bad checksum
315 */
316 SKB_GSO_SHARED_FRAG = 1 << 6,
317}; 317};
318 318
319#if BITS_PER_LONG > 32 319#if BITS_PER_LONG > 32
@@ -2220,7 +2220,8 @@ static inline int skb_linearize(struct sk_buff *skb)
2220 */ 2220 */
2221static inline bool skb_has_shared_frag(const struct sk_buff *skb) 2221static inline bool skb_has_shared_frag(const struct sk_buff *skb)
2222{ 2222{
2223 return skb_shinfo(skb)->gso_type & SKB_GSO_SHARED_FRAG; 2223 return skb_is_nonlinear(skb) &&
2224 skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
2224} 2225}
2225 2226
2226/** 2227/**
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 21a22cce6e53..6c1ad09f8796 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2326,8 +2326,7 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
2326{ 2326{
2327 int pos = skb_headlen(skb); 2327 int pos = skb_headlen(skb);
2328 2328
2329 skb_shinfo(skb1)->gso_type = skb_shinfo(skb)->gso_type; 2329 skb_shinfo(skb)->tx_flags = skb_shinfo(skb1)->tx_flags & SKBTX_SHARED_FRAG;
2330
2331 if (len < pos) /* Split line is inside header. */ 2330 if (len < pos) /* Split line is inside header. */
2332 skb_split_inside_header(skb, skb1, len, pos); 2331 skb_split_inside_header(skb, skb1, len, pos);
2333 else /* Second chunk has no header, nothing to copy. */ 2332 else /* Second chunk has no header, nothing to copy. */
@@ -2833,7 +2832,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2833 skb_copy_from_linear_data_offset(skb, offset, 2832 skb_copy_from_linear_data_offset(skb, offset,
2834 skb_put(nskb, hsize), hsize); 2833 skb_put(nskb, hsize), hsize);
2835 2834
2836 skb_shinfo(nskb)->gso_type = skb_shinfo(skb)->gso_type; 2835 skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
2837 2836
2838 while (pos < offset + len && i < nfrags) { 2837 while (pos < offset + len && i < nfrags) {
2839 *frag = skb_shinfo(skb)->frags[i]; 2838 *frag = skb_shinfo(skb)->frags[i];
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 1aec92bf8018..e6e5d8506336 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1287,7 +1287,6 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
1287 SKB_GSO_UDP | 1287 SKB_GSO_UDP |
1288 SKB_GSO_DODGY | 1288 SKB_GSO_DODGY |
1289 SKB_GSO_TCP_ECN | 1289 SKB_GSO_TCP_ECN |
1290 SKB_GSO_SHARED_FRAG |
1291 0))) 1290 0)))
1292 goto out; 1291 goto out;
1293 1292
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 3e98ed2bff55..5e12dca7b3dd 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -598,6 +598,7 @@ slow_path:
598 /* for offloaded checksums cleanup checksum before fragmentation */ 598 /* for offloaded checksums cleanup checksum before fragmentation */
599 if ((skb->ip_summed == CHECKSUM_PARTIAL) && skb_checksum_help(skb)) 599 if ((skb->ip_summed == CHECKSUM_PARTIAL) && skb_checksum_help(skb))
600 goto fail; 600 goto fail;
601 iph = ip_hdr(skb);
601 602
602 left = skb->len - hlen; /* Space per frame */ 603 left = skb->len - hlen; /* Space per frame */
603 ptr = hlen; /* Where to start from */ 604 ptr = hlen; /* Where to start from */
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 801b07b796f0..1f0bedb8622f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -897,8 +897,7 @@ new_segment:
897 get_page(page); 897 get_page(page);
898 skb_fill_page_desc(skb, i, page, offset, copy); 898 skb_fill_page_desc(skb, i, page, offset, copy);
899 } 899 }
900 900 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
901 skb_shinfo(skb)->gso_type |= SKB_GSO_SHARED_FRAG;
902 901
903 skb->len += copy; 902 skb->len += copy;
904 skb->data_len += copy; 903 skb->data_len += copy;
@@ -3044,7 +3043,6 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
3044 SKB_GSO_DODGY | 3043 SKB_GSO_DODGY |
3045 SKB_GSO_TCP_ECN | 3044 SKB_GSO_TCP_ECN |
3046 SKB_GSO_TCPV6 | 3045 SKB_GSO_TCPV6 |
3047 SKB_GSO_SHARED_FRAG |
3048 0) || 3046 0) ||
3049 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) 3047 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
3050 goto out; 3048 goto out;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index d9bfaea34322..a759e19496d2 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1239,13 +1239,13 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
1239 */ 1239 */
1240 if (!skb_shinfo(prev)->gso_size) { 1240 if (!skb_shinfo(prev)->gso_size) {
1241 skb_shinfo(prev)->gso_size = mss; 1241 skb_shinfo(prev)->gso_size = mss;
1242 skb_shinfo(prev)->gso_type |= sk->sk_gso_type; 1242 skb_shinfo(prev)->gso_type = sk->sk_gso_type;
1243 } 1243 }
1244 1244
1245 /* CHECKME: To clear or not to clear? Mimics normal skb currently */ 1245 /* CHECKME: To clear or not to clear? Mimics normal skb currently */
1246 if (skb_shinfo(skb)->gso_segs <= 1) { 1246 if (skb_shinfo(skb)->gso_segs <= 1) {
1247 skb_shinfo(skb)->gso_size = 0; 1247 skb_shinfo(skb)->gso_size = 0;
1248 skb_shinfo(skb)->gso_type &= SKB_GSO_SHARED_FRAG; 1248 skb_shinfo(skb)->gso_type = 0;
1249 } 1249 }
1250 1250
1251 /* Difference in this won't matter, both ACKed by the same cumul. ACK */ 1251 /* Difference in this won't matter, both ACKed by the same cumul. ACK */
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 564bf89d9fd3..6182d90e97b0 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1133,7 +1133,6 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
1133static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, 1133static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
1134 unsigned int mss_now) 1134 unsigned int mss_now)
1135{ 1135{
1136 skb_shinfo(skb)->gso_type &= SKB_GSO_SHARED_FRAG;
1137 if (skb->len <= mss_now || !sk_can_gso(sk) || 1136 if (skb->len <= mss_now || !sk_can_gso(sk) ||
1138 skb->ip_summed == CHECKSUM_NONE) { 1137 skb->ip_summed == CHECKSUM_NONE) {
1139 /* Avoid the costly divide in the normal 1138 /* Avoid the costly divide in the normal
@@ -1141,10 +1140,11 @@ static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb,
1141 */ 1140 */
1142 skb_shinfo(skb)->gso_segs = 1; 1141 skb_shinfo(skb)->gso_segs = 1;
1143 skb_shinfo(skb)->gso_size = 0; 1142 skb_shinfo(skb)->gso_size = 0;
1143 skb_shinfo(skb)->gso_type = 0;
1144 } else { 1144 } else {
1145 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now); 1145 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now);
1146 skb_shinfo(skb)->gso_size = mss_now; 1146 skb_shinfo(skb)->gso_size = mss_now;
1147 skb_shinfo(skb)->gso_type |= sk->sk_gso_type; 1147 skb_shinfo(skb)->gso_type = sk->sk_gso_type;
1148 } 1148 }
1149} 1149}
1150 1150
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index d141fc32a2ea..f26f0da7f095 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -100,7 +100,6 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
100 SKB_GSO_DODGY | 100 SKB_GSO_DODGY |
101 SKB_GSO_TCP_ECN | 101 SKB_GSO_TCP_ECN |
102 SKB_GSO_TCPV6 | 102 SKB_GSO_TCPV6 |
103 SKB_GSO_SHARED_FRAG |
104 0))) 103 0)))
105 goto out; 104 goto out;
106 105