Commit 74696496 authored by Litao Jiao's avatar Litao Jiao
Browse files

net/smc: align the connect behaviour with TCP

mainline inclusion
from mainline-v5.19-rc1
commit 3aba1030
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6TK1U
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3aba103006bcc4a7472b7c9506b3bc065ffb7992



--------------------------------

Connect with O_NONBLOCK will not be completed immediately
and returns -EINPROGRESS. It is possible to use selector/poll
for completion by selecting the socket for writing. After select
indicates writability, a second connect function call will return
0 to indicate connected successfully as TCP does, but smc returns
-EISCONN. Use socket state for smc to indicate connect state, which
can help smc aligning the connect behaviour with TCP.

Signed-off-by: default avatarGuangguan Wang <guangguan.wang@linux.alibaba.com>
Acked-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarLitao Jiao <jiaolitao@sangfor.com.cn>
parent 22bae0fc
Loading
Loading
Loading
Loading
+46 −4
Original line number Diff line number Diff line
@@ -1097,9 +1097,29 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr,
		goto out_err;

	lock_sock(sk);
	switch (sock->state) {
	default:
		rc = -EINVAL;
		goto out;
	case SS_CONNECTED:
		rc = sk->sk_state == SMC_ACTIVE ? -EISCONN : -EINVAL;
		goto out;
	case SS_CONNECTING:
		if (sk->sk_state == SMC_ACTIVE)
			goto connected;
		break;
	case SS_UNCONNECTED:
		sock->state = SS_CONNECTING;
		break;
	}

	switch (sk->sk_state) {
	default:
		goto out;
	case SMC_CLOSED:
		rc = sock_error(sk) ? : -ECONNABORTED;
		sock->state = SS_UNCONNECTED;
		goto out;
	case SMC_ACTIVE:
		rc = -EISCONN;
		goto out;
@@ -1118,21 +1138,25 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr,
	if (rc && rc != -EINPROGRESS)
		goto out;

	if (smc->use_fallback)
	if (smc->use_fallback) {
		sock->state = rc ? SS_CONNECTING : SS_CONNECTED;
		goto out;
	}
	sock_hold(&smc->sk); /* sock put in passive closing */
	if (flags & O_NONBLOCK) {
		if (queue_work(smc_hs_wq, &smc->connect_work))
			smc->connect_nonblock = 1;
		rc = -EINPROGRESS;
		goto out;
	} else {
		rc = __smc_connect(smc);
		if (rc < 0)
			goto out;
		else
			rc = 0; /* success cases including fallback */
	}

connected:
	rc = 0;
	sock->state = SS_CONNECTED;
out:
	release_sock(sk);
out_err:
@@ -1234,6 +1258,7 @@ struct sock *smc_accept_dequeue(struct sock *parent,
		}
		if (new_sock) {
			sock_graft(new_sk, new_sock);
			new_sock->state = SS_CONNECTED;
			if (isk->use_fallback) {
				smc_sk(new_sk)->clcsock->file = new_sock->file;
				isk->clcsock->file->private_data = isk->clcsock;
@@ -1864,7 +1889,7 @@ static int smc_listen(struct socket *sock, int backlog)

	rc = -EINVAL;
	if ((sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) ||
	    smc->connect_nonblock)
	    smc->connect_nonblock || sock->state != SS_UNCONNECTED)
		goto out;

	rc = 0;
@@ -2134,6 +2159,17 @@ static int smc_shutdown(struct socket *sock, int how)

	lock_sock(sk);

	if (sock->state == SS_CONNECTING) {
		if (sk->sk_state == SMC_ACTIVE)
			sock->state = SS_CONNECTED;
		else if (sk->sk_state == SMC_PEERCLOSEWAIT1 ||
			 sk->sk_state == SMC_PEERCLOSEWAIT2 ||
			 sk->sk_state == SMC_APPCLOSEWAIT1 ||
			 sk->sk_state == SMC_APPCLOSEWAIT2 ||
			 sk->sk_state == SMC_APPFINCLOSEWAIT)
			sock->state = SS_DISCONNECTING;
	}

	rc = -ENOTCONN;
	if ((sk->sk_state != SMC_ACTIVE) &&
	    (sk->sk_state != SMC_PEERCLOSEWAIT1) &&
@@ -2147,6 +2183,7 @@ static int smc_shutdown(struct socket *sock, int how)
		sk->sk_shutdown = smc->clcsock->sk->sk_shutdown;
		if (sk->sk_shutdown == SHUTDOWN_MASK) {
			sk->sk_state = SMC_CLOSED;
			sk->sk_socket->state = SS_UNCONNECTED;
			sock_put(sk);
		}
		goto out;
@@ -2172,6 +2209,10 @@ static int smc_shutdown(struct socket *sock, int how)
	/* map sock_shutdown_cmd constants to sk_shutdown value range */
	sk->sk_shutdown |= how + 1;

	if (sk->sk_state == SMC_CLOSED)
		sock->state = SS_UNCONNECTED;
	else
		sock->state = SS_DISCONNECTING;
out:
	release_sock(sk);
	return rc ? rc : rc1;
@@ -2463,6 +2504,7 @@ static int smc_create(struct net *net, struct socket *sock, int protocol,

	rc = -ENOBUFS;
	sock->ops = &smc_sock_ops;
	sock->state = SS_UNCONNECTED;
	sk = smc_sock_alloc(net, sock, protocol);
	if (!sk)
		goto out;