aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_output.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2018-03-31 16:16:25 -0400
committerDavid S. Miller <davem@davemloft.net>2018-04-01 14:08:21 -0400
commit694aba690de062cf27b28a5e56e7a5a7185b0a1c (patch)
tree1fbdc27ecff23dc1babcf50d1fd9884d84d800ee /net/ipv4/ip_output.c
parentc07255020551cadae8bf903f2c5e1fcbad731bac (diff)
ipv4: factorize sk_wmem_alloc updates done by __ip_append_data()
While testing my inet defrag changes, I found that the senders could spend ~20% of cpu cycles in skb_set_owner_w() updating sk->sk_wmem_alloc for every fragment they cook. The solution to this problem is to use alloc_skb() instead of sock_wmalloc() and manually perform a single sk_wmem_alloc change. Similar change for IPv6 is provided in following patch. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ip_output.c')
-rw-r--r--net/ipv4/ip_output.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 66340ab750e6..94cacae76aca 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -876,6 +876,7 @@ static int __ip_append_data(struct sock *sk,
876 unsigned int maxfraglen, fragheaderlen, maxnonfragsize; 876 unsigned int maxfraglen, fragheaderlen, maxnonfragsize;
877 int csummode = CHECKSUM_NONE; 877 int csummode = CHECKSUM_NONE;
878 struct rtable *rt = (struct rtable *)cork->dst; 878 struct rtable *rt = (struct rtable *)cork->dst;
879 unsigned int wmem_alloc_delta = 0;
879 u32 tskey = 0; 880 u32 tskey = 0;
880 881
881 skb = skb_peek_tail(queue); 882 skb = skb_peek_tail(queue);
@@ -971,11 +972,10 @@ alloc_new_skb:
971 (flags & MSG_DONTWAIT), &err); 972 (flags & MSG_DONTWAIT), &err);
972 } else { 973 } else {
973 skb = NULL; 974 skb = NULL;
974 if (refcount_read(&sk->sk_wmem_alloc) <= 975 if (refcount_read(&sk->sk_wmem_alloc) + wmem_alloc_delta <=
975 2 * sk->sk_sndbuf) 976 2 * sk->sk_sndbuf)
976 skb = sock_wmalloc(sk, 977 skb = alloc_skb(alloclen + hh_len + 15,
977 alloclen + hh_len + 15, 1, 978 sk->sk_allocation);
978 sk->sk_allocation);
979 if (unlikely(!skb)) 979 if (unlikely(!skb))
980 err = -ENOBUFS; 980 err = -ENOBUFS;
981 } 981 }
@@ -1033,6 +1033,11 @@ alloc_new_skb:
1033 /* 1033 /*
1034 * Put the packet on the pending queue. 1034 * Put the packet on the pending queue.
1035 */ 1035 */
1036 if (!skb->destructor) {
1037 skb->destructor = sock_wfree;
1038 skb->sk = sk;
1039 wmem_alloc_delta += skb->truesize;
1040 }
1036 __skb_queue_tail(queue, skb); 1041 __skb_queue_tail(queue, skb);
1037 continue; 1042 continue;
1038 } 1043 }
@@ -1079,12 +1084,13 @@ alloc_new_skb:
1079 skb->len += copy; 1084 skb->len += copy;
1080 skb->data_len += copy; 1085 skb->data_len += copy;
1081 skb->truesize += copy; 1086 skb->truesize += copy;
1082 refcount_add(copy, &sk->sk_wmem_alloc); 1087 wmem_alloc_delta += copy;
1083 } 1088 }
1084 offset += copy; 1089 offset += copy;
1085 length -= copy; 1090 length -= copy;
1086 } 1091 }
1087 1092
1093 refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
1088 return 0; 1094 return 0;
1089 1095
1090error_efault: 1096error_efault:
@@ -1092,6 +1098,7 @@ error_efault:
1092error: 1098error:
1093 cork->length -= length; 1099 cork->length -= length;
1094 IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); 1100 IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS);
1101 refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
1095 return err; 1102 return err;
1096} 1103}
1097 1104