mptcp: Use per-subflow storage for DATA_FIN sequence number
authorMat Martineau <mathew.j.martineau@linux.intel.com>
Fri, 28 Feb 2020 23:47:40 +0000 (15:47 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Mar 2020 01:01:43 +0000 (17:01 -0800)
Instead of reading the MPTCP-level sequence number when sending DATA_FIN,
store the data in the subflow so it can be safely accessed when the
subflow TCP headers are written to the packet without the MPTCP-level
lock held. This also allows the MPTCP-level socket to close individual
subflows without closing the MPTCP connection.

Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/mptcp/options.c
net/mptcp/protocol.c
net/mptcp/protocol.h

index 45acd877bef345259ca2a84c58cd0d375f88386f..90c81953ec2c565572f5f9c339d6f5cc12333329 100644 (file)
@@ -312,7 +312,7 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
                 */
                ext->use_map = 1;
                ext->dsn64 = 1;
-               ext->data_seq = mptcp_sk(subflow->conn)->write_seq;
+               ext->data_seq = subflow->data_fin_tx_seq;
                ext->subflow_seq = 0;
                ext->data_len = 1;
        } else {
@@ -354,8 +354,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
                if (mpext)
                        opts->ext_copy = *mpext;
 
-               if (skb && tcp_fin &&
-                   subflow->conn->sk_state != TCP_ESTABLISHED)
+               if (skb && tcp_fin && subflow->data_fin_tx_enable)
                        mptcp_write_data_fin(subflow, &opts->ext_copy);
                ret = true;
        }
index 07559b45eec5190957697f8a5de357eab78f5e01..4c075a9f7ed00975a546e26a51dce79f6964f5ed 100644 (file)
@@ -720,7 +720,8 @@ static void mptcp_cancel_work(struct sock *sk)
                sock_put(sk);
 }
 
-static void mptcp_subflow_shutdown(struct sock *ssk, int how)
+static void mptcp_subflow_shutdown(struct sock *ssk, int how,
+                                  bool data_fin_tx_enable, u64 data_fin_tx_seq)
 {
        lock_sock(ssk);
 
@@ -733,6 +734,14 @@ static void mptcp_subflow_shutdown(struct sock *ssk, int how)
                tcp_disconnect(ssk, O_NONBLOCK);
                break;
        default:
+               if (data_fin_tx_enable) {
+                       struct mptcp_subflow_context *subflow;
+
+                       subflow = mptcp_subflow_ctx(ssk);
+                       subflow->data_fin_tx_seq = data_fin_tx_seq;
+                       subflow->data_fin_tx_enable = 1;
+               }
+
                ssk->sk_shutdown |= how;
                tcp_shutdown(ssk, how);
                break;
@@ -749,6 +758,7 @@ static void mptcp_close(struct sock *sk, long timeout)
        struct mptcp_subflow_context *subflow, *tmp;
        struct mptcp_sock *msk = mptcp_sk(sk);
        LIST_HEAD(conn_list);
+       u64 data_fin_tx_seq;
 
        lock_sock(sk);
 
@@ -757,11 +767,15 @@ static void mptcp_close(struct sock *sk, long timeout)
 
        list_splice_init(&msk->conn_list, &conn_list);
 
+       data_fin_tx_seq = msk->write_seq;
+
        release_sock(sk);
 
        list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
 
+               subflow->data_fin_tx_seq = data_fin_tx_seq;
+               subflow->data_fin_tx_enable = 1;
                __mptcp_close_ssk(sk, ssk, subflow, timeout);
        }
 
@@ -854,7 +868,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
                        *err = -ENOBUFS;
                        local_bh_enable();
                        release_sock(sk);
-                       mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1);
+                       mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1, 0, 0);
                        tcp_close(newsk, 0);
                        return NULL;
                }
@@ -1309,7 +1323,7 @@ static int mptcp_shutdown(struct socket *sock, int how)
        mptcp_for_each_subflow(msk, subflow) {
                struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);
 
-               mptcp_subflow_shutdown(tcp_sk, how);
+               mptcp_subflow_shutdown(tcp_sk, how, 1, msk->write_seq);
        }
 
 out_unlock:
index 6c0b2c8ab674509bc73d1707e8f5ccccb5083c90..313558fa8185b7a63594aadd9f3e3bb67e47fa4a 100644 (file)
@@ -125,7 +125,9 @@ struct mptcp_subflow_context {
                mpc_map : 1,
                data_avail : 1,
                rx_eof : 1,
+               data_fin_tx_enable : 1,
                can_ack : 1;        /* only after processing the remote a key */
+       u64     data_fin_tx_seq;
 
        struct  sock *tcp_sock;     /* tcp sk backpointer */
        struct  sock *conn;         /* parent mptcp_sock */