Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion drivers/nvme/target/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,19 @@ static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue)

static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status)
{
/*
* Keep rcv_state at RECV_ERR even for the internal -ESHUTDOWN path.
* nvmet_tcp_handle_icreq() can return -ESHUTDOWN after the ICReq has
* already been consumed and queue teardown has started.
*
* If nvmet_tcp_data_ready() or nvmet_tcp_write_space() queues
* nvmet_tcp_io_work() again before nvmet_tcp_release_queue_work()
* cancels it, the queue must not keep that old receive state.
* Otherwise the next nvmet_tcp_io_work() run can reach
* nvmet_tcp_done_recv_pdu() and try to handle the same ICReq again.
*
* That is why queue->rcv_state needs to be updated before we return.
*/
queue->rcv_state = NVMET_TCP_RECV_ERR;
if (status == -EPIPE || status == -ECONNRESET)
kernel_sock_shutdown(queue->sock, SHUT_RDWR);
Expand Down Expand Up @@ -906,10 +919,24 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
iov.iov_base = icresp;
iov.iov_len = sizeof(*icresp);
ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
if (ret < 0)
if (ret < 0) {
spin_lock_bh(&queue->state_lock);
if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
spin_unlock_bh(&queue->state_lock);
return -ESHUTDOWN;
}
spin_unlock_bh(&queue->state_lock);
return ret; /* queue removal will cleanup */
}

spin_lock_bh(&queue->state_lock);
if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
spin_unlock_bh(&queue->state_lock);
/* Tell nvmet_tcp_socket_error() teardown is in progress. */
return -ESHUTDOWN;
}
queue->state = NVMET_TCP_Q_LIVE;
spin_unlock_bh(&queue->state_lock);
nvmet_prepare_receive_pdu(queue);
return 0;
}
Expand Down
4 changes: 3 additions & 1 deletion include/net/inet_connection_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ struct inet_connection_sock_af_ops {
struct request_sock *req,
struct dst_entry *dst,
struct request_sock *req_unhash,
bool *own_req);
bool *own_req,
void (*opt_child_init)(struct sock *newsk,
const struct sock *sk));
u16 net_header_len;
u16 net_frag_header_len;
u16 sockaddr_len;
Expand Down
4 changes: 3 additions & 1 deletion include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct dst_entry *dst,
struct request_sock *req_unhash,
bool *own_req);
bool *own_req,
void (*opt_child_init)(struct sock *newsk,
const struct sock *sk));
int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb);
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
int tcp_connect(struct sock *sk);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/syncookies.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb,
bool own_req;

child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst,
NULL, &own_req);
NULL, &own_req, NULL);
if (child) {
refcount_set(&req->rsk_refcnt, 1);
tcp_sk(child)->tsoffset = tsoff;
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_fastopen.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
req->sk = NULL;

child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL,
NULL, &own_req);
NULL, &own_req, NULL);
if (!child)
return NULL;

Expand Down
8 changes: 7 additions & 1 deletion net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1446,7 +1446,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct dst_entry *dst,
struct request_sock *req_unhash,
bool *own_req)
bool *own_req,
void (*opt_child_init)(struct sock *newsk,
const struct sock *sk))
{
struct inet_request_sock *ireq;
bool found_dup_sk = false;
Expand Down Expand Up @@ -1494,6 +1496,10 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
}
sk_setup_caps(newsk, dst);

#if IS_ENABLED(CONFIG_IPV6)
if (opt_child_init)
opt_child_init(newsk, sk);
#endif
tcp_ca_openreq_child(newsk, dst);

tcp_sync_mss(newsk, dst_mtu(dst));
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/tcp_minisocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
* socket is created, wait for troubles.
*/
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL,
req, &own_req);
req, &own_req, NULL);
if (!child)
goto listen_overflow;

Expand Down
102 changes: 45 additions & 57 deletions net/ipv6/tcp_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -1119,11 +1119,51 @@ static void tcp_v6_restore_cb(struct sk_buff *skb)
sizeof(struct inet6_skb_parm));
}

/* Called from tcp_v4_syn_recv_sock() for v6_mapped children. */
static void tcp_v6_mapped_child_init(struct sock *newsk, const struct sock *sk)
{
struct inet_sock *newinet = inet_sk(newsk);
struct tcp6_sock *newtcp6sk;
struct ipv6_pinfo *newnp = inet6_sk(newsk);
const struct ipv6_pinfo *np = inet6_sk(sk);

newtcp6sk = (struct tcp6_sock *)newsk;
inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;

memcpy(newnp, np, sizeof(struct ipv6_pinfo));

newnp->saddr = newsk->sk_v6_rcv_saddr;

inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
if (sk_is_mptcp(newsk))
mptcpv6_handle_mapped(newsk, true);
newsk->sk_backlog_rcv = tcp_v4_do_rcv;
#if CONFIG_TCP_MD5SIG
tcp_sk(newsk)->af_specific = &tcp_sock_ipv6_mapped_specific;
#endif

newnp->ipv6_mc_list = NULL;
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
newnp->pktoptions = NULL;
newnp->opt = NULL;

/* tcp_v4_syn_recv_sock() has initialized newinet->mc_{index,ttl} */
newnp->mcast_oif = newinet->mc_index;
newnp->mcast_hops = newinet->mc_ttl;

newnp->rcv_flowinfo = 0;
if (np->repflow)
newnp->flow_label = 0;
}

static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct dst_entry *dst,
struct request_sock *req_unhash,
bool *own_req)
bool *own_req,
void (*opt_child_init)(struct sock *newsk,
const struct sock *sk))
{
struct inet_request_sock *ireq;
struct ipv6_pinfo *newnp;
Expand All @@ -1139,62 +1179,10 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
#endif
struct flowi6 fl6;

if (skb->protocol == htons(ETH_P_IP)) {
/*
* v6 mapped
*/

newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst,
req_unhash, own_req);

if (!newsk)
return NULL;

newtcp6sk = (struct tcp6_sock *)newsk;
inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;

newinet = inet_sk(newsk);
newnp = inet6_sk(newsk);
newtp = tcp_sk(newsk);

memcpy(newnp, np, sizeof(struct ipv6_pinfo));

newnp->saddr = newsk->sk_v6_rcv_saddr;

inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;
if (sk_is_mptcp(newsk))
mptcpv6_handle_mapped(newsk, true);
newsk->sk_backlog_rcv = tcp_v4_do_rcv;
#ifdef CONFIG_TCP_MD5SIG
newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
#endif

newnp->ipv6_mc_list = NULL;
newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL;
newnp->pktoptions = NULL;
newnp->opt = NULL;
newnp->mcast_oif = inet_iif(skb);
newnp->mcast_hops = ip_hdr(skb)->ttl;
newnp->rcv_flowinfo = 0;
if (np->repflow)
newnp->flow_label = 0;

/*
* No need to charge this sock to the relevant IPv6 refcnt debug socks count
* here, tcp_create_openreq_child now does this for us, see the comment in
* that function for the gory details. -acme
*/

/* It is tricky place. Until this moment IPv4 tcp
worked with IPv6 icsk.icsk_af_ops.
Sync it now.
*/
tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);

return newsk;
}

if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_syn_recv_sock(sk, skb, req, dst,
req_unhash, own_req,
tcp_v6_mapped_child_init);
ireq = inet_rsk(req);

if (sk_acceptq_is_full(sk))
Expand Down
2 changes: 2 additions & 0 deletions net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -3598,6 +3598,8 @@ int __init mptcp_proto_v6_init(void)
{
int err;

mptcp_subflow_v6_init();

mptcp_v6_prot = mptcp_prot;
strcpy(mptcp_v6_prot.name, "MPTCPv6");
mptcp_v6_prot.slab = NULL;
Expand Down
1 change: 1 addition & 0 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
void __init mptcp_proto_init(void);
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
int __init mptcp_proto_v6_init(void);
void __init mptcp_subflow_v6_init(void);
#endif

struct sock *mptcp_sk_clone(const struct sock *sk,
Expand Down
21 changes: 13 additions & 8 deletions net/mptcp/subflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,9 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
struct request_sock *req,
struct dst_entry *dst,
struct request_sock *req_unhash,
bool *own_req)
bool *own_req,
void (*opt_child_init)(struct sock *newsk,
const struct sock *sk))
{
struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk);
struct mptcp_subflow_request_sock *subflow_req;
Expand Down Expand Up @@ -677,7 +679,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,

create_child:
child = listener->icsk_af_ops->syn_recv_sock(sk, skb, req, dst,
req_unhash, own_req);
req_unhash, own_req, opt_child_init);

if (child && *own_req) {
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(child);
Expand Down Expand Up @@ -1731,7 +1733,15 @@ void __init mptcp_subflow_init(void)
tcp_prot_override = tcp_prot;
tcp_prot_override.release_cb = tcp_release_cb_override;

mptcp_diag_subflow_init(&subflow_ulp_ops);

if (tcp_register_ulp(&subflow_ulp_ops) != 0)
panic("MPTCP: failed to register subflows to ULP\n");
}

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
void __init mptcp_subflow_v6_init(void)
{
subflow_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops;
subflow_request_sock_ipv6_ops.route_req = subflow_v6_route_req;

Expand All @@ -1749,10 +1759,5 @@ void __init mptcp_subflow_init(void)

tcpv6_prot_override = tcpv6_prot;
tcpv6_prot_override.release_cb = tcp_release_cb_override;
#endif

mptcp_diag_subflow_init(&subflow_ulp_ops);

if (tcp_register_ulp(&subflow_ulp_ops) != 0)
panic("MPTCP: failed to register subflows to ULP\n");
}
#endif