Commit b796d04b authored by Paolo Abeni's avatar Paolo Abeni Committed by Jakub Kicinski

tcp: factor out tcp_build_frag()

Will be needed by the next patch, as MPTCP needs to handle
directly the error/memory-allocation-needed path.

No functional changes intended.

Additionally let MPTCP code access the tcp_remove_empty_skb()
helper.
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent c0a645a7
...@@ -322,6 +322,7 @@ void tcp_shutdown(struct sock *sk, int how); ...@@ -322,6 +322,7 @@ void tcp_shutdown(struct sock *sk, int how);
int tcp_v4_early_demux(struct sk_buff *skb); int tcp_v4_early_demux(struct sk_buff *skb);
int tcp_v4_rcv(struct sk_buff *skb); int tcp_v4_rcv(struct sk_buff *skb);
void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb);
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size); int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size);
...@@ -329,6 +330,8 @@ int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, ...@@ -329,6 +330,8 @@ int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
int flags); int flags);
int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
size_t size, int flags); size_t size, int flags);
struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
struct page *page, int offset, size_t *size);
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
size_t size, int flags); size_t size, int flags);
int tcp_send_mss(struct sock *sk, int *size_goal, int flags); int tcp_send_mss(struct sock *sk, int *size_goal, int flags);
......
...@@ -954,7 +954,7 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags) ...@@ -954,7 +954,7 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
* importantly be able to generate EPOLLOUT for Edge Trigger epoll() * importantly be able to generate EPOLLOUT for Edge Trigger epoll()
* users. * users.
*/ */
static void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb) void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
{ {
if (skb && !skb->len) { if (skb && !skb->len) {
tcp_unlink_write_queue(skb, sk); tcp_unlink_write_queue(skb, sk);
...@@ -964,55 +964,24 @@ static void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb) ...@@ -964,55 +964,24 @@ static void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
} }
} }
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
size_t size, int flags) struct page *page, int offset, size_t *size)
{ {
struct tcp_sock *tp = tcp_sk(sk);
int mss_now, size_goal;
int err;
ssize_t copied;
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
if (IS_ENABLED(CONFIG_DEBUG_VM) &&
WARN_ONCE(!sendpage_ok(page),
"page must not be a Slab one and have page_count > 0"))
return -EINVAL;
/* Wait for a connection to finish. One exception is TCP Fast Open
* (passive side) where data is allowed to be sent before a connection
* is fully established.
*/
if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) &&
!tcp_passive_fastopen(sk)) {
err = sk_stream_wait_connect(sk, &timeo);
if (err != 0)
goto out_err;
}
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
mss_now = tcp_send_mss(sk, &size_goal, flags);
copied = 0;
err = -EPIPE;
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
goto out_err;
while (size > 0) {
struct sk_buff *skb = tcp_write_queue_tail(sk); struct sk_buff *skb = tcp_write_queue_tail(sk);
int copy, i; struct tcp_sock *tp = tcp_sk(sk);
bool can_coalesce; bool can_coalesce;
int copy, i;
if (!skb || (copy = size_goal - skb->len) <= 0 || if (!skb || (copy = size_goal - skb->len) <= 0 ||
!tcp_skb_can_collapse_to(skb)) { !tcp_skb_can_collapse_to(skb)) {
new_segment: new_segment:
if (!sk_stream_memory_free(sk)) if (!sk_stream_memory_free(sk))
goto wait_for_space; return NULL;
skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation, skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation,
tcp_rtx_and_write_queues_empty(sk)); tcp_rtx_and_write_queues_empty(sk));
if (!skb) if (!skb)
goto wait_for_space; return NULL;
#ifdef CONFIG_TLS_DEVICE #ifdef CONFIG_TLS_DEVICE
skb->decrypted = !!(flags & MSG_SENDPAGE_DECRYPTED); skb->decrypted = !!(flags & MSG_SENDPAGE_DECRYPTED);
...@@ -1021,8 +990,8 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, ...@@ -1021,8 +990,8 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
copy = size_goal; copy = size_goal;
} }
if (copy > size) if (copy > *size)
copy = size; copy = *size;
i = skb_shinfo(skb)->nr_frags; i = skb_shinfo(skb)->nr_frags;
can_coalesce = skb_can_coalesce(skb, i, page, offset); can_coalesce = skb_can_coalesce(skb, i, page, offset);
...@@ -1031,7 +1000,7 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, ...@@ -1031,7 +1000,7 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
goto new_segment; goto new_segment;
} }
if (!sk_wmem_schedule(sk, copy)) if (!sk_wmem_schedule(sk, copy))
goto wait_for_space; return NULL;
if (can_coalesce) { if (can_coalesce) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
...@@ -1053,6 +1022,52 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, ...@@ -1053,6 +1022,52 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
TCP_SKB_CB(skb)->end_seq += copy; TCP_SKB_CB(skb)->end_seq += copy;
tcp_skb_pcount_set(skb, 0); tcp_skb_pcount_set(skb, 0);
*size = copy;
return skb;
}
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
size_t size, int flags)
{
struct tcp_sock *tp = tcp_sk(sk);
int mss_now, size_goal;
int err;
ssize_t copied;
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
if (IS_ENABLED(CONFIG_DEBUG_VM) &&
WARN_ONCE(!sendpage_ok(page),
"page must not be a Slab one and have page_count > 0"))
return -EINVAL;
/* Wait for a connection to finish. One exception is TCP Fast Open
* (passive side) where data is allowed to be sent before a connection
* is fully established.
*/
if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) &&
!tcp_passive_fastopen(sk)) {
err = sk_stream_wait_connect(sk, &timeo);
if (err != 0)
goto out_err;
}
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
mss_now = tcp_send_mss(sk, &size_goal, flags);
copied = 0;
err = -EPIPE;
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
goto out_err;
while (size > 0) {
struct sk_buff *skb;
size_t copy = size;
skb = tcp_build_frag(sk, size_goal, flags, page, offset, &copy);
if (!skb)
goto wait_for_space;
if (!copied) if (!copied)
TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment