Skip to content

Commit 15cc104

Browse files
Paolo Abenidavem330
authored andcommitted
mptcp: deliver ssk errors to msk
Currently all errors received on msk subflows are ignored. We need to catch at least the errors on connect() and on fallback sockets. Use a custom sk_error_report callback at subflow level, and do the real action under the msk socket lock - via the usual sock_owned_by_user()/release_callback() schema. Fixes: 6e628cd ("mptcp: use mptcp release_cb for delayed tasks") Signed-off-by: Paolo Abeni <[email protected]> Signed-off-by: Mat Martineau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4c0d2e9 commit 15cc104

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

net/mptcp/protocol.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,6 +2959,8 @@ static void mptcp_release_cb(struct sock *sk)
29592959
mptcp_push_pending(sk, 0);
29602960
spin_lock_bh(&sk->sk_lock.slock);
29612961
}
2962+
if (test_and_clear_bit(MPTCP_ERROR_REPORT, &mptcp_sk(sk)->flags))
2963+
__mptcp_error_report(sk);
29622964

29632965
/* clear any wmem reservation and errors */
29642966
__mptcp_update_wmem(sk);
@@ -3355,6 +3357,11 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
33553357
if (sk->sk_shutdown & RCV_SHUTDOWN)
33563358
mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
33573359

3360+
/* This barrier is coupled with smp_wmb() in tcp_reset() */
3361+
smp_rmb();
3362+
if (sk->sk_err)
3363+
mask |= EPOLLERR;
3364+
33583365
return mask;
33593366
}
33603367

net/mptcp/protocol.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
#define MPTCP_WORK_CLOSE_SUBFLOW 5
9696
#define MPTCP_PUSH_PENDING 6
9797
#define MPTCP_CLEAN_UNA 7
98+
#define MPTCP_ERROR_REPORT 8
9899

99100
static inline bool before64(__u64 seq1, __u64 seq2)
100101
{
@@ -414,6 +415,7 @@ struct mptcp_subflow_context {
414415
void (*tcp_data_ready)(struct sock *sk);
415416
void (*tcp_state_change)(struct sock *sk);
416417
void (*tcp_write_space)(struct sock *sk);
418+
void (*tcp_error_report)(struct sock *sk);
417419

418420
struct rcu_head rcu;
419421
};
@@ -478,6 +480,7 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
478480
sk->sk_data_ready = ctx->tcp_data_ready;
479481
sk->sk_state_change = ctx->tcp_state_change;
480482
sk->sk_write_space = ctx->tcp_write_space;
483+
sk->sk_error_report = ctx->tcp_error_report;
481484

482485
inet_csk(sk)->icsk_af_ops = ctx->icsk_af_ops;
483486
}
@@ -505,6 +508,7 @@ bool mptcp_finish_join(struct sock *sk);
505508
bool mptcp_schedule_work(struct sock *sk);
506509
void __mptcp_check_push(struct sock *sk, struct sock *ssk);
507510
void __mptcp_data_acked(struct sock *sk);
511+
void __mptcp_error_report(struct sock *sk);
508512
void mptcp_subflow_eof(struct sock *sk);
509513
bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit);
510514
void __mptcp_flush_join_list(struct mptcp_sock *msk);

net/mptcp/subflow.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,46 @@ static void subflow_write_space(struct sock *ssk)
10431043
/* we take action in __mptcp_clean_una() */
10441044
}
10451045

1046+
void __mptcp_error_report(struct sock *sk)
1047+
{
1048+
struct mptcp_subflow_context *subflow;
1049+
struct mptcp_sock *msk = mptcp_sk(sk);
1050+
1051+
mptcp_for_each_subflow(msk, subflow) {
1052+
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
1053+
int err = sock_error(ssk);
1054+
1055+
if (!err)
1056+
continue;
1057+
1058+
/* only propagate errors on fallen-back sockets or
1059+
* on MPC connect
1060+
*/
1061+
if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(msk))
1062+
continue;
1063+
1064+
inet_sk_state_store(sk, inet_sk_state_load(ssk));
1065+
sk->sk_err = -err;
1066+
1067+
/* This barrier is coupled with smp_rmb() in mptcp_poll() */
1068+
smp_wmb();
1069+
sk->sk_error_report(sk);
1070+
break;
1071+
}
1072+
}
1073+
1074+
static void subflow_error_report(struct sock *ssk)
1075+
{
1076+
struct sock *sk = mptcp_subflow_ctx(ssk)->conn;
1077+
1078+
mptcp_data_lock(sk);
1079+
if (!sock_owned_by_user(sk))
1080+
__mptcp_error_report(sk);
1081+
else
1082+
set_bit(MPTCP_ERROR_REPORT, &mptcp_sk(sk)->flags);
1083+
mptcp_data_unlock(sk);
1084+
}
1085+
10461086
static struct inet_connection_sock_af_ops *
10471087
subflow_default_af_ops(struct sock *sk)
10481088
{
@@ -1352,9 +1392,11 @@ static int subflow_ulp_init(struct sock *sk)
13521392
ctx->tcp_data_ready = sk->sk_data_ready;
13531393
ctx->tcp_state_change = sk->sk_state_change;
13541394
ctx->tcp_write_space = sk->sk_write_space;
1395+
ctx->tcp_error_report = sk->sk_error_report;
13551396
sk->sk_data_ready = subflow_data_ready;
13561397
sk->sk_write_space = subflow_write_space;
13571398
sk->sk_state_change = subflow_state_change;
1399+
sk->sk_error_report = subflow_error_report;
13581400
out:
13591401
return err;
13601402
}
@@ -1407,6 +1449,7 @@ static void subflow_ulp_clone(const struct request_sock *req,
14071449
new_ctx->tcp_data_ready = old_ctx->tcp_data_ready;
14081450
new_ctx->tcp_state_change = old_ctx->tcp_state_change;
14091451
new_ctx->tcp_write_space = old_ctx->tcp_write_space;
1452+
new_ctx->tcp_error_report = old_ctx->tcp_error_report;
14101453
new_ctx->rel_write_seq = 1;
14111454
new_ctx->tcp_sock = newsk;
14121455

0 commit comments

Comments
 (0)