diff options
author | Eric Dumazet <edumazet@google.com> | 2014-02-20 13:09:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-02-22 00:05:21 -0500 |
commit | f5ddcbbb40aa0ba7fbfe22355d287603dbeeaaac (patch) | |
tree | 891b56a6481cf19747018c832be557613e5b5a02 | |
parent | 68ad785c007246490b220ae958b544671339059b (diff) |
net-tcp: fastopen: fix high order allocations
This patch fixes two bugs in fastopen :
1) The tcp_sendmsg(..., @size) argument was ignored.
Code was relying on user not fooling the kernel with iovec mismatches
2) When MTU is about 64KB, tcp_send_syn_data() attempts order-5
allocations, which are likely to fail when memory gets fragmented.
Fixes: 783237e8daf13 ("net-tcp: Fast Open client - sending SYN-data")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Acked-by: Yuchung Cheng <ycheng@google.com>
Tested-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/tcp.h | 3 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 8 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 7 |
3 files changed, 13 insertions, 5 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 56fc366da6d5..8c4dd63134d4 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -1303,7 +1303,8 @@ struct tcp_fastopen_request { | |||
1303 | /* Fast Open cookie. Size 0 means a cookie request */ | 1303 | /* Fast Open cookie. Size 0 means a cookie request */ |
1304 | struct tcp_fastopen_cookie cookie; | 1304 | struct tcp_fastopen_cookie cookie; |
1305 | struct msghdr *data; /* data in MSG_FASTOPEN */ | 1305 | struct msghdr *data; /* data in MSG_FASTOPEN */ |
1306 | u16 copied; /* queued in tcp_connect() */ | 1306 | size_t size; |
1307 | int copied; /* queued in tcp_connect() */ | ||
1307 | }; | 1308 | }; |
1308 | void tcp_free_fastopen_req(struct tcp_sock *tp); | 1309 | void tcp_free_fastopen_req(struct tcp_sock *tp); |
1309 | 1310 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9f3a2db9109e..97c8f5620c43 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1044,7 +1044,8 @@ void tcp_free_fastopen_req(struct tcp_sock *tp) | |||
1044 | } | 1044 | } |
1045 | } | 1045 | } |
1046 | 1046 | ||
1047 | static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size) | 1047 | static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, |
1048 | int *copied, size_t size) | ||
1048 | { | 1049 | { |
1049 | struct tcp_sock *tp = tcp_sk(sk); | 1050 | struct tcp_sock *tp = tcp_sk(sk); |
1050 | int err, flags; | 1051 | int err, flags; |
@@ -1059,11 +1060,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size) | |||
1059 | if (unlikely(tp->fastopen_req == NULL)) | 1060 | if (unlikely(tp->fastopen_req == NULL)) |
1060 | return -ENOBUFS; | 1061 | return -ENOBUFS; |
1061 | tp->fastopen_req->data = msg; | 1062 | tp->fastopen_req->data = msg; |
1063 | tp->fastopen_req->size = size; | ||
1062 | 1064 | ||
1063 | flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; | 1065 | flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; |
1064 | err = __inet_stream_connect(sk->sk_socket, msg->msg_name, | 1066 | err = __inet_stream_connect(sk->sk_socket, msg->msg_name, |
1065 | msg->msg_namelen, flags); | 1067 | msg->msg_namelen, flags); |
1066 | *size = tp->fastopen_req->copied; | 1068 | *copied = tp->fastopen_req->copied; |
1067 | tcp_free_fastopen_req(tp); | 1069 | tcp_free_fastopen_req(tp); |
1068 | return err; | 1070 | return err; |
1069 | } | 1071 | } |
@@ -1083,7 +1085,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1083 | 1085 | ||
1084 | flags = msg->msg_flags; | 1086 | flags = msg->msg_flags; |
1085 | if (flags & MSG_FASTOPEN) { | 1087 | if (flags & MSG_FASTOPEN) { |
1086 | err = tcp_sendmsg_fastopen(sk, msg, &copied_syn); | 1088 | err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size); |
1087 | if (err == -EINPROGRESS && copied_syn > 0) | 1089 | if (err == -EINPROGRESS && copied_syn > 0) |
1088 | goto out; | 1090 | goto out; |
1089 | else if (err) | 1091 | else if (err) |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 3be16727f058..09805817627b 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -2908,7 +2908,12 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) | |||
2908 | space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) - | 2908 | space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) - |
2909 | MAX_TCP_OPTION_SPACE; | 2909 | MAX_TCP_OPTION_SPACE; |
2910 | 2910 | ||
2911 | syn_data = skb_copy_expand(syn, skb_headroom(syn), space, | 2911 | space = min_t(size_t, space, fo->size); |
2912 | |||
2913 | /* limit to order-0 allocations */ | ||
2914 | space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER)); | ||
2915 | |||
2916 | syn_data = skb_copy_expand(syn, MAX_TCP_HEADER, space, | ||
2912 | sk->sk_allocation); | 2917 | sk->sk_allocation); |
2913 | if (syn_data == NULL) | 2918 | if (syn_data == NULL) |
2914 | goto fallback; | 2919 | goto fallback; |