Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
mptcp: Don't take meta-lock when receiving third ACK
Browse files Browse the repository at this point in the history
Now everything is ready to do this in a lockless way.

Simply, in tcp_v4(6)_rcv, stop taking the meta-level lock.
When creating the initial subflow, we currently are also holding the
meta-level lock. We need to drop this one as soon as we handover control
to the subflow (aka., when exiting mptcp_check_req_master()).

Data-reception however still requires the meta-level lock. Thus, we need
to take it again in tcp_child_process().

Signed-off-by: Christoph Paasch <cpaasch@apple.com>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
  • Loading branch information
cpaasch authored and matttbe committed May 2, 2018
1 parent 7a662b6 commit 4966859
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 77 deletions.
41 changes: 4 additions & 37 deletions net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1730,45 +1730,16 @@ int tcp_v4_rcv(struct sk_buff *skb)
inet_csk_reqsk_queue_drop_and_put(sk, req);
goto lookup;
}
if (unlikely(is_meta_sk(sk) && !mptcp_can_new_subflow(sk))) {
inet_csk_reqsk_queue_drop_and_put(sk, req);
goto lookup;
}
/* We own a reference on the listener, increase it again
* as we might lose it too soon.
*/
sock_hold(sk);
refcounted = true;

if (is_meta_sk(sk)) {
bh_lock_sock(sk);

if (!mptcp_can_new_subflow(sk)) {
inet_csk_reqsk_queue_drop_and_put(sk, req);
bh_unlock_sock(sk);

goto discard_and_relse;
}

if (sock_owned_by_user(sk)) {
th = (const struct tcphdr *)skb->data;
iph = ip_hdr(skb);
tcp_v4_fill_cb(skb, iph, th);

skb->sk = sk;
if (unlikely(sk_add_backlog(sk, skb,
sk->sk_rcvbuf + sk->sk_sndbuf))) {
reqsk_put(req);

bh_unlock_sock(sk);
__NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP);
goto discard_and_relse;
}

reqsk_put(req);
bh_unlock_sock(sk);
sock_put(sk);

return 0;
}
}

nsk = NULL;
if (!tcp_filter(sk, skb)) {
th = (const struct tcphdr *)skb->data;
Expand All @@ -1778,15 +1749,11 @@ int tcp_v4_rcv(struct sk_buff *skb)
}
if (!nsk) {
reqsk_put(req);
if (is_meta_sk(sk))
bh_unlock_sock(sk);
goto discard_and_relse;
}
if (nsk == sk) {
reqsk_put(req);
tcp_v4_restore_cb(skb);
if (is_meta_sk(sk))
bh_unlock_sock(sk);
} else if (tcp_child_process(sk, nsk, skb)) {
tcp_v4_send_reset(nsk, skb);
goto discard_and_relse;
Expand Down
9 changes: 7 additions & 2 deletions net/ipv4/tcp_minisocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,11 @@ int tcp_child_process(struct sock *parent, struct sock *child,
sk_mark_napi_id(child, skb);

tcp_segs_in(tcp_sk(child), skb);
/* The following will be removed when we allow lockless data-reception
* on the subflows.
*/
if (mptcp(tcp_sk(child)))
bh_lock_sock(meta_sk);
if (!sock_owned_by_user(meta_sk)) {
ret = tcp_rcv_state_process(child, skb);
/* Wakeup parent, send SIGIO */
Expand All @@ -912,9 +917,9 @@ int tcp_child_process(struct sock *parent, struct sock *child,
__sk_add_backlog(meta_sk, skb);
}

bh_unlock_sock(child);
if (mptcp(tcp_sk(child)))
bh_unlock_sock(child);
bh_unlock_sock(meta_sk);
bh_unlock_sock(meta_sk);
sock_put(child);
return ret;
}
Expand Down
41 changes: 4 additions & 37 deletions net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -1521,42 +1521,13 @@ static int tcp_v6_rcv(struct sk_buff *skb)
inet_csk_reqsk_queue_drop_and_put(sk, req);
goto lookup;
}
if (unlikely(is_meta_sk(sk) && !mptcp_can_new_subflow(sk))) {
inet_csk_reqsk_queue_drop_and_put(sk, req);
goto lookup;
}
sock_hold(sk);
refcounted = true;

if (is_meta_sk(sk)) {
bh_lock_sock(sk);

if (!mptcp_can_new_subflow(sk)) {
inet_csk_reqsk_queue_drop_and_put(sk, req);
bh_unlock_sock(sk);

goto discard_and_relse;
}

if (sock_owned_by_user(sk)) {
th = (const struct tcphdr *)skb->data;
hdr = ipv6_hdr(skb);
tcp_v6_fill_cb(skb, hdr, th);

skb->sk = sk;
if (unlikely(sk_add_backlog(sk, skb,
sk->sk_rcvbuf + sk->sk_sndbuf))) {
reqsk_put(req);

bh_unlock_sock(sk);
__NET_INC_STATS(net, LINUX_MIB_TCPBACKLOGDROP);
goto discard_and_relse;
}

reqsk_put(req);
bh_unlock_sock(sk);
sock_put(sk);

return 0;
}
}

nsk = NULL;
if (!tcp_filter(sk, skb)) {
th = (const struct tcphdr *)skb->data;
Expand All @@ -1566,14 +1537,10 @@ static int tcp_v6_rcv(struct sk_buff *skb)
}
if (!nsk) {
reqsk_put(req);
if (is_meta_sk(sk))
bh_unlock_sock(sk);
goto discard_and_relse;
}
if (nsk == sk) {
reqsk_put(req);
if (is_meta_sk(sk))
bh_unlock_sock(sk);
tcp_v6_restore_cb(skb);
} else if (tcp_child_process(sk, nsk, skb)) {
tcp_v6_send_reset(nsk, skb);
Expand Down
13 changes: 13 additions & 0 deletions net/mptcp/mptcp_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,7 @@ static u8 mptcp_set_new_pathindex(struct mptcp_cb *mpcb)
return i;
}

/* May be called without holding the meta-level lock */
int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id,
gfp_t flags)
{
Expand Down Expand Up @@ -2112,6 +2113,11 @@ int mptcp_check_req_fastopen(struct sock *child, struct request_sock *req)
/* Handled by the master_sk */
tcp_sk(meta_sk)->fastopen_rsk = NULL;

/* Subflow establishment is now lockless, drop the lock here it will
* be taken again in tcp_child_process().
*/
bh_unlock_sock(meta_sk);

return 0;
}

Expand Down Expand Up @@ -2141,9 +2147,15 @@ int mptcp_check_req_master(struct sock *sk, struct sock *child,
inet_csk_reqsk_queue_add(sk, req, meta_sk);
}

/* Subflow establishment is now lockless, drop the lock here it will
* be taken again in tcp_child_process().
*/
bh_unlock_sock(meta_sk);

return 0;
}

/* May be called without holding the meta-level lock */
struct sock *mptcp_check_req_child(struct sock *meta_sk,
struct sock *child,
struct request_sock *req,
Expand Down Expand Up @@ -2386,6 +2398,7 @@ void mptcp_tsq_sub_deferred(struct sock *meta_sk)
}
}

/* May be called without holding the meta-level lock */
void mptcp_join_reqsk_init(const struct mptcp_cb *mpcb,
const struct request_sock *req,
struct sk_buff *skb)
Expand Down
5 changes: 4 additions & 1 deletion net/mptcp/mptcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ static u32 mptcp_v4_cookie_init_seq(struct request_sock *req, const struct sock
}
#endif

/* May be called without holding the meta-level lock */
static int mptcp_v4_join_init_req(struct request_sock *req, const struct sock *meta_sk,
struct sk_buff *skb, bool want_cookie)
{
Expand Down Expand Up @@ -141,7 +142,9 @@ struct request_sock_ops mptcp_request_sock_ops __read_mostly = {
.syn_ack_timeout = tcp_syn_ack_timeout,
};

/* Similar to: tcp_v4_conn_request */
/* Similar to: tcp_v4_conn_request
* May be called without holding the meta-level lock
*/
static int mptcp_v4_join_request(struct sock *meta_sk, struct sk_buff *skb)
{
return tcp_conn_request(&mptcp_request_sock_ops,
Expand Down
4 changes: 4 additions & 0 deletions net/mptcp/mptcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static u32 mptcp_v6_cookie_init_seq(struct request_sock *req, const struct sock
}
#endif

/* May be called without holding the meta-level lock */
static int mptcp_v6_join_init_req(struct request_sock *req, const struct sock *meta_sk,
struct sk_buff *skb, bool want_cookie)
{
Expand Down Expand Up @@ -170,6 +171,9 @@ struct request_sock_ops mptcp6_request_sock_ops __read_mostly = {
.syn_ack_timeout = tcp_syn_ack_timeout,
};

/* Similar to: tcp_v6_conn_request
* May be called without holding the meta-level lock
*/
static int mptcp_v6_join_request(struct sock *meta_sk, struct sk_buff *skb)
{
return tcp_conn_request(&mptcp6_request_sock_ops,
Expand Down

0 comments on commit 4966859

Please sign in to comment.