提交 69800e51 编写于 作者: P Paolo Abeni 提交者: David S. Miller

mptcp: propagate fastclose error

When an mptcp socket is closed due to an incoming FASTCLOSE
option, so specific sk_err is set and later syscall will
fail usually with EPIPE.

Align the current fastclose error handling with TCP reset,
properly setting the socket error according to the current
msk state and propagating such error.

Additionally sendmsg() is currently not handling properly
the sk_err, always returning EPIPE.
Reviewed-by: NMatthieu Baerts <matthieu.baerts@tessares.net>
Reviewed-by: NMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: NPaolo Abeni <pabeni@redhat.com>
Signed-off-by: NMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 7171e8a1
...@@ -1707,7 +1707,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1707,7 +1707,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
goto out; goto out;
} else if (ret) { } else if (ret) {
release_sock(ssk); release_sock(ssk);
goto out; goto do_error;
} }
release_sock(ssk); release_sock(ssk);
} }
...@@ -1717,9 +1717,13 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1717,9 +1717,13 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
ret = sk_stream_wait_connect(sk, &timeo); ret = sk_stream_wait_connect(sk, &timeo);
if (ret) if (ret)
goto out; goto do_error;
} }
ret = -EPIPE;
if (unlikely(sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)))
goto do_error;
pfrag = sk_page_frag(sk); pfrag = sk_page_frag(sk);
while (msg_data_left(msg)) { while (msg_data_left(msg)) {
...@@ -1728,11 +1732,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1728,11 +1732,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
bool dfrag_collapsed; bool dfrag_collapsed;
size_t psize, offset; size_t psize, offset;
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) {
ret = -EPIPE;
goto out;
}
/* reuse tail pfrag, if possible, or carve a new one from the /* reuse tail pfrag, if possible, or carve a new one from the
* page allocator * page allocator
*/ */
...@@ -1764,7 +1763,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1764,7 +1763,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
if (copy_page_from_iter(dfrag->page, offset, psize, if (copy_page_from_iter(dfrag->page, offset, psize,
&msg->msg_iter) != psize) { &msg->msg_iter) != psize) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto do_error;
} }
/* data successfully copied into the write queue */ /* data successfully copied into the write queue */
...@@ -1796,7 +1795,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1796,7 +1795,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
__mptcp_push_pending(sk, msg->msg_flags); __mptcp_push_pending(sk, msg->msg_flags);
ret = sk_stream_wait_memory(sk, &timeo); ret = sk_stream_wait_memory(sk, &timeo);
if (ret) if (ret)
goto out; goto do_error;
} }
if (copied) if (copied)
...@@ -1804,7 +1803,14 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1804,7 +1803,14 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
out: out:
release_sock(sk); release_sock(sk);
return copied ? : ret; return copied;
do_error:
if (copied)
goto out;
copied = sk_stream_error(sk, msg->msg_flags, ret);
goto out;
} }
static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk, static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk,
...@@ -2441,12 +2447,31 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk) ...@@ -2441,12 +2447,31 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
unlock_sock_fast(tcp_sk, slow); unlock_sock_fast(tcp_sk, slow);
} }
/* Mirror the tcp_reset() error propagation */
switch (sk->sk_state) {
case TCP_SYN_SENT:
sk->sk_err = ECONNREFUSED;
break;
case TCP_CLOSE_WAIT:
sk->sk_err = EPIPE;
break;
case TCP_CLOSE:
return;
default:
sk->sk_err = ECONNRESET;
}
inet_sk_state_store(sk, TCP_CLOSE); inet_sk_state_store(sk, TCP_CLOSE);
sk->sk_shutdown = SHUTDOWN_MASK; sk->sk_shutdown = SHUTDOWN_MASK;
smp_mb__before_atomic(); /* SHUTDOWN must be visible first */ smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags); set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags);
mptcp_close_wake_up(sk); /* the calling mptcp_worker will properly destroy the socket */
if (sock_flag(sk, SOCK_DEAD))
return;
sk->sk_state_change(sk);
sk_error_report(sk);
} }
static void __mptcp_retrans(struct sock *sk) static void __mptcp_retrans(struct sock *sk)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册