Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0a092eb authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'smc-next'



Ursula Braun says:

====================
net/smc: patches 2019-04-12

here are patches for SMC:
* patch 1 improves behavior of non-blocking connect
* patches 2, 3, 5, 7, and 8 improve connecting return codes
* patches 4 and 6 are a cleanups without functional change
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6dc400af 7a62725a
Loading
Loading
Loading
Loading
+182 −173
Original line number Diff line number Diff line
@@ -134,11 +134,9 @@ static int smc_release(struct socket *sock)
	smc = smc_sk(sk);

	/* cleanup for a dangling non-blocking connect */
	if (smc->connect_info && sk->sk_state == SMC_INIT)
	if (smc->connect_nonblock && sk->sk_state == SMC_INIT)
		tcp_abort(smc->clcsock->sk, ECONNABORTED);
	flush_work(&smc->connect_work);
	kfree(smc->connect_info);
	smc->connect_info = NULL;

	if (sk->sk_state == SMC_LISTEN)
		/* smc_close_non_accepted() is called and acquires
@@ -452,6 +450,7 @@ static int smc_connect_fallback(struct smc_sock *smc, int reason_code)
	smc->use_fallback = true;
	smc->fallback_rsn = reason_code;
	smc_copy_sock_settings_to_clc(smc);
	smc->connect_nonblock = 0;
	if (smc->sk.sk_state == SMC_INIT)
		smc->sk.sk_state = SMC_ACTIVE;
	return 0;
@@ -491,46 +490,41 @@ static int smc_connect_abort(struct smc_sock *smc, int reason_code,
		mutex_unlock(&smc_client_lgr_pending);

	smc_conn_free(&smc->conn);
	smc->connect_nonblock = 0;
	return reason_code;
}

/* check if there is a rdma device available for this connection. */
/* called for connect and listen */
static int smc_check_rdma(struct smc_sock *smc, struct smc_ib_device **ibdev,
			  u8 *ibport, unsigned short vlan_id, u8 gid[])
static int smc_find_rdma_device(struct smc_sock *smc, struct smc_init_info *ini)
{
	int reason_code = 0;

	/* PNET table look up: search active ib_device and port
	 * within same PNETID that also contains the ethernet device
	 * used for the internal TCP socket
	 */
	smc_pnet_find_roce_resource(smc->clcsock->sk, ibdev, ibport, vlan_id,
				    gid);
	if (!(*ibdev))
		reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */

	return reason_code;
	smc_pnet_find_roce_resource(smc->clcsock->sk, ini);
	if (!ini->ib_dev)
		return SMC_CLC_DECL_NOSMCRDEV;
	return 0;
}

/* check if there is an ISM device available for this connection. */
/* called for connect and listen */
static int smc_check_ism(struct smc_sock *smc, struct smcd_dev **ismdev)
static int smc_find_ism_device(struct smc_sock *smc, struct smc_init_info *ini)
{
	/* Find ISM device with same PNETID as connecting interface  */
	smc_pnet_find_ism_resource(smc->clcsock->sk, ismdev);
	if (!(*ismdev))
		return SMC_CLC_DECL_CNFERR; /* configuration error */
	smc_pnet_find_ism_resource(smc->clcsock->sk, ini);
	if (!ini->ism_dev)
		return SMC_CLC_DECL_NOSMCDDEV;
	return 0;
}

/* Check for VLAN ID and register it on ISM device just for CLC handshake */
static int smc_connect_ism_vlan_setup(struct smc_sock *smc,
				      struct smcd_dev *ismdev,
				      unsigned short vlan_id)
				      struct smc_init_info *ini)
{
	if (vlan_id && smc_ism_get_vlan(ismdev, vlan_id))
		return SMC_CLC_DECL_CNFERR;
	if (ini->vlan_id && smc_ism_get_vlan(ini->ism_dev, ini->vlan_id))
		return SMC_CLC_DECL_ISMVLANERR;
	return 0;
}

@@ -538,12 +532,11 @@ static int smc_connect_ism_vlan_setup(struct smc_sock *smc,
 * used, the VLAN ID will be registered again during the connection setup.
 */
static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc, bool is_smcd,
					struct smcd_dev *ismdev,
					unsigned short vlan_id)
					struct smc_init_info *ini)
{
	if (!is_smcd)
		return 0;
	if (vlan_id && smc_ism_put_vlan(ismdev, vlan_id))
	if (ini->vlan_id && smc_ism_put_vlan(ini->ism_dev, ini->vlan_id))
		return SMC_CLC_DECL_CNFERR;
	return 0;
}
@@ -551,13 +544,12 @@ static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc, bool is_smcd,
/* CLC handshake during connect */
static int smc_connect_clc(struct smc_sock *smc, int smc_type,
			   struct smc_clc_msg_accept_confirm *aclc,
			   struct smc_ib_device *ibdev, u8 ibport,
			   u8 gid[], struct smcd_dev *ismdev)
			   struct smc_init_info *ini)
{
	int rc = 0;

	/* do inband token exchange */
	rc = smc_clc_send_proposal(smc, smc_type, ibdev, ibport, gid, ismdev);
	rc = smc_clc_send_proposal(smc, smc_type, ini);
	if (rc)
		return rc;
	/* receive SMC Accept CLC message */
@@ -568,23 +560,19 @@ static int smc_connect_clc(struct smc_sock *smc, int smc_type,
/* setup for RDMA connection of client */
static int smc_connect_rdma(struct smc_sock *smc,
			    struct smc_clc_msg_accept_confirm *aclc,
			    struct smc_ib_device *ibdev, u8 ibport)
			    struct smc_init_info *ini)
{
	int local_contact = SMC_FIRST_CONTACT;
	struct smc_link *link;
	int reason_code = 0;

	ini->is_smcd = false;
	ini->ib_lcl = &aclc->lcl;
	ini->ib_clcqpn = ntoh24(aclc->qpn);
	ini->srv_first_contact = aclc->hdr.flag;

	mutex_lock(&smc_client_lgr_pending);
	local_contact = smc_conn_create(smc, false, aclc->hdr.flag, ibdev,
					ibport, ntoh24(aclc->qpn), &aclc->lcl,
					NULL, 0);
	if (local_contact < 0) {
		if (local_contact == -ENOMEM)
			reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/
		else if (local_contact == -ENOLINK)
			reason_code = SMC_CLC_DECL_SYNCERR; /* synchr. error */
		else
			reason_code = SMC_CLC_DECL_INTERR; /* other error */
	reason_code = smc_conn_create(smc, ini);
	if (reason_code) {
		mutex_unlock(&smc_client_lgr_pending);
		return reason_code;
	}
@@ -594,45 +582,48 @@ static int smc_connect_rdma(struct smc_sock *smc,

	/* create send buffer and rmb */
	if (smc_buf_create(smc, false))
		return smc_connect_abort(smc, SMC_CLC_DECL_MEM, local_contact);
		return smc_connect_abort(smc, SMC_CLC_DECL_MEM,
					 ini->cln_first_contact);

	if (local_contact == SMC_FIRST_CONTACT)
	if (ini->cln_first_contact == SMC_FIRST_CONTACT)
		smc_link_save_peer_info(link, aclc);

	if (smc_rmb_rtoken_handling(&smc->conn, aclc))
		return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RTOK,
					 local_contact);
					 ini->cln_first_contact);

	smc_close_init(smc);
	smc_rx_init(smc);

	if (local_contact == SMC_FIRST_CONTACT) {
	if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
		if (smc_ib_ready_link(link))
			return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RDYLNK,
						 local_contact);
						 ini->cln_first_contact);
	} else {
		if (smc_reg_rmb(link, smc->conn.rmb_desc, true))
			return smc_connect_abort(smc, SMC_CLC_DECL_ERR_REGRMB,
						 local_contact);
						 ini->cln_first_contact);
	}
	smc_rmb_sync_sg_for_device(&smc->conn);

	reason_code = smc_clc_send_confirm(smc);
	if (reason_code)
		return smc_connect_abort(smc, reason_code, local_contact);
		return smc_connect_abort(smc, reason_code,
					 ini->cln_first_contact);

	smc_tx_init(smc);

	if (local_contact == SMC_FIRST_CONTACT) {
	if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
		/* QP confirmation over RoCE fabric */
		reason_code = smc_clnt_conf_first_link(smc);
		if (reason_code)
			return smc_connect_abort(smc, reason_code,
						 local_contact);
						 ini->cln_first_contact);
	}
	mutex_unlock(&smc_client_lgr_pending);

	smc_copy_sock_settings_to_clc(smc);
	smc->connect_nonblock = 0;
	if (smc->sk.sk_state == SMC_INIT)
		smc->sk.sk_state = SMC_ACTIVE;

@@ -642,23 +633,26 @@ static int smc_connect_rdma(struct smc_sock *smc,
/* setup for ISM connection of client */
static int smc_connect_ism(struct smc_sock *smc,
			   struct smc_clc_msg_accept_confirm *aclc,
			   struct smcd_dev *ismdev)
			   struct smc_init_info *ini)
{
	int local_contact = SMC_FIRST_CONTACT;
	int rc = 0;

	ini->is_smcd = true;
	ini->ism_gid = aclc->gid;
	ini->srv_first_contact = aclc->hdr.flag;

	/* there is only one lgr role for SMC-D; use server lock */
	mutex_lock(&smc_server_lgr_pending);
	local_contact = smc_conn_create(smc, true, aclc->hdr.flag, NULL, 0, 0,
					NULL, ismdev, aclc->gid);
	if (local_contact < 0) {
	rc = smc_conn_create(smc, ini);
	if (rc) {
		mutex_unlock(&smc_server_lgr_pending);
		return SMC_CLC_DECL_MEM;
		return rc;
	}

	/* Create send and receive buffers */
	if (smc_buf_create(smc, true))
		return smc_connect_abort(smc, SMC_CLC_DECL_MEM, local_contact);
		return smc_connect_abort(smc, SMC_CLC_DECL_MEM,
					 ini->cln_first_contact);

	smc_conn_save_peer_info(smc, aclc);
	smc_close_init(smc);
@@ -667,10 +661,11 @@ static int smc_connect_ism(struct smc_sock *smc,

	rc = smc_clc_send_confirm(smc);
	if (rc)
		return smc_connect_abort(smc, rc, local_contact);
		return smc_connect_abort(smc, rc, ini->cln_first_contact);
	mutex_unlock(&smc_server_lgr_pending);

	smc_copy_sock_settings_to_clc(smc);
	smc->connect_nonblock = 0;
	if (smc->sk.sk_state == SMC_INIT)
		smc->sk.sk_state = SMC_ACTIVE;

@@ -682,13 +677,9 @@ static int __smc_connect(struct smc_sock *smc)
{
	bool ism_supported = false, rdma_supported = false;
	struct smc_clc_msg_accept_confirm aclc;
	struct smc_ib_device *ibdev;
	struct smcd_dev *ismdev;
	u8 gid[SMC_GID_SIZE];
	unsigned short vlan;
	struct smc_init_info ini = {0};
	int smc_type;
	int rc = 0;
	u8 ibport;

	sock_hold(&smc->sk); /* sock put in passive closing */

@@ -703,20 +694,21 @@ static int __smc_connect(struct smc_sock *smc)
	if (using_ipsec(smc))
		return smc_connect_decline_fallback(smc, SMC_CLC_DECL_IPSEC);

	/* check for VLAN ID */
	if (smc_vlan_by_tcpsk(smc->clcsock, &vlan))
		return smc_connect_decline_fallback(smc, SMC_CLC_DECL_CNFERR);
	/* get vlan id from IP device */
	if (smc_vlan_by_tcpsk(smc->clcsock, &ini))
		return smc_connect_decline_fallback(smc,
						    SMC_CLC_DECL_GETVLANERR);

	/* check if there is an ism device available */
	if (!smc_check_ism(smc, &ismdev) &&
	    !smc_connect_ism_vlan_setup(smc, ismdev, vlan)) {
	if (!smc_find_ism_device(smc, &ini) &&
	    !smc_connect_ism_vlan_setup(smc, &ini)) {
		/* ISM is supported for this connection */
		ism_supported = true;
		smc_type = SMC_TYPE_D;
	}

	/* check if there is a rdma device available */
	if (!smc_check_rdma(smc, &ibdev, &ibport, vlan, gid)) {
	if (!smc_find_rdma_device(smc, &ini)) {
		/* RDMA is supported for this connection */
		rdma_supported = true;
		if (ism_supported)
@@ -730,25 +722,25 @@ static int __smc_connect(struct smc_sock *smc)
		return smc_connect_decline_fallback(smc, SMC_CLC_DECL_NOSMCDEV);

	/* perform CLC handshake */
	rc = smc_connect_clc(smc, smc_type, &aclc, ibdev, ibport, gid, ismdev);
	rc = smc_connect_clc(smc, smc_type, &aclc, &ini);
	if (rc) {
		smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
		smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini);
		return smc_connect_decline_fallback(smc, rc);
	}

	/* depending on previous steps, connect using rdma or ism */
	if (rdma_supported && aclc.hdr.path == SMC_TYPE_R)
		rc = smc_connect_rdma(smc, &aclc, ibdev, ibport);
		rc = smc_connect_rdma(smc, &aclc, &ini);
	else if (ism_supported && aclc.hdr.path == SMC_TYPE_D)
		rc = smc_connect_ism(smc, &aclc, ismdev);
		rc = smc_connect_ism(smc, &aclc, &ini);
	else
		rc = SMC_CLC_DECL_MODEUNSUPP;
	if (rc) {
		smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
		smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini);
		return smc_connect_decline_fallback(smc, rc);
	}

	smc_connect_ism_vlan_cleanup(smc, ism_supported, ismdev, vlan);
	smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini);
	return 0;
}

@@ -756,17 +748,30 @@ static void smc_connect_work(struct work_struct *work)
{
	struct smc_sock *smc = container_of(work, struct smc_sock,
					    connect_work);
	int rc;
	long timeo = smc->sk.sk_sndtimeo;
	int rc = 0;

	lock_sock(&smc->sk);
	rc = kernel_connect(smc->clcsock, &smc->connect_info->addr,
			    smc->connect_info->alen, smc->connect_info->flags);
	if (!timeo)
		timeo = MAX_SCHEDULE_TIMEOUT;
	lock_sock(smc->clcsock->sk);
	if (smc->clcsock->sk->sk_err) {
		smc->sk.sk_err = smc->clcsock->sk->sk_err;
		goto out;
	} else if ((1 << smc->clcsock->sk->sk_state) &
					(TCPF_SYN_SENT | TCP_SYN_RECV)) {
		rc = sk_stream_wait_connect(smc->clcsock->sk, &timeo);
		if ((rc == -EPIPE) &&
		    ((1 << smc->clcsock->sk->sk_state) &
					(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)))
			rc = 0;
	}
	if (rc < 0) {
		smc->sk.sk_err = -rc;
	release_sock(smc->clcsock->sk);
	lock_sock(&smc->sk);
	if (rc != 0 || smc->sk.sk_err) {
		smc->sk.sk_state = SMC_CLOSED;
		if (rc == -EPIPE || rc == -EAGAIN)
			smc->sk.sk_err = EPIPE;
		else if (signal_pending(current))
			smc->sk.sk_err = -sock_intr_errno(timeo);
		goto out;
	}

@@ -779,8 +784,6 @@ static void smc_connect_work(struct work_struct *work)
		smc->sk.sk_state_change(&smc->sk);
	else
		smc->sk.sk_write_space(&smc->sk);
	kfree(smc->connect_info);
	smc->connect_info = NULL;
	release_sock(&smc->sk);
}

@@ -813,26 +816,18 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr,

	smc_copy_sock_settings_to_clc(smc);
	tcp_sk(smc->clcsock->sk)->syn_smc = 1;
	if (flags & O_NONBLOCK) {
		if (smc->connect_info) {
	if (smc->connect_nonblock) {
		rc = -EALREADY;
		goto out;
	}
		smc->connect_info = kzalloc(alen + 2 * sizeof(int), GFP_KERNEL);
		if (!smc->connect_info) {
			rc = -ENOMEM;
	rc = kernel_connect(smc->clcsock, addr, alen, flags);
	if (rc && rc != -EINPROGRESS)
		goto out;
		}
		smc->connect_info->alen = alen;
		smc->connect_info->flags = flags ^ O_NONBLOCK;
		memcpy(&smc->connect_info->addr, addr, alen);
		schedule_work(&smc->connect_work);
	if (flags & O_NONBLOCK) {
		if (schedule_work(&smc->connect_work))
			smc->connect_nonblock = 1;
		rc = -EINPROGRESS;
	} else {
		rc = kernel_connect(smc->clcsock, addr, alen, flags);
		if (rc)
			goto out;

		rc = __smc_connect(smc);
		if (rc < 0)
			goto out;
@@ -1099,7 +1094,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
}

/* listen worker: check prefixes */
static int smc_listen_rdma_check(struct smc_sock *new_smc,
static int smc_listen_prfx_check(struct smc_sock *new_smc,
				 struct smc_clc_msg_proposal *pclc)
{
	struct smc_clc_msg_proposal_prefix *pclc_prfx;
@@ -1107,25 +1102,21 @@ static int smc_listen_rdma_check(struct smc_sock *new_smc,

	pclc_prfx = smc_clc_proposal_get_prefix(pclc);
	if (smc_clc_prfx_match(newclcsock, pclc_prfx))
		return SMC_CLC_DECL_CNFERR;
		return SMC_CLC_DECL_DIFFPREFIX;

	return 0;
}

/* listen worker: initialize connection and buffers */
static int smc_listen_rdma_init(struct smc_sock *new_smc,
				struct smc_clc_msg_proposal *pclc,
				struct smc_ib_device *ibdev, u8 ibport,
				int *local_contact)
				struct smc_init_info *ini)
{
	int rc;

	/* allocate connection / link group */
	*local_contact = smc_conn_create(new_smc, false, 0, ibdev, ibport, 0,
					 &pclc->lcl, NULL, 0);
	if (*local_contact < 0) {
		if (*local_contact == -ENOMEM)
			return SMC_CLC_DECL_MEM;/* insufficient memory*/
		return SMC_CLC_DECL_INTERR; /* other error */
	}
	rc = smc_conn_create(new_smc, ini);
	if (rc)
		return rc;

	/* create send buffer and rmb */
	if (smc_buf_create(new_smc, false))
@@ -1137,33 +1128,30 @@ static int smc_listen_rdma_init(struct smc_sock *new_smc,
/* listen worker: initialize connection and buffers for SMC-D */
static int smc_listen_ism_init(struct smc_sock *new_smc,
			       struct smc_clc_msg_proposal *pclc,
			       struct smcd_dev *ismdev,
			       int *local_contact)
			       struct smc_init_info *ini)
{
	struct smc_clc_msg_smcd *pclc_smcd;
	int rc;

	pclc_smcd = smc_get_clc_msg_smcd(pclc);
	*local_contact = smc_conn_create(new_smc, true, 0, NULL, 0, 0, NULL,
					 ismdev, pclc_smcd->gid);
	if (*local_contact < 0) {
		if (*local_contact == -ENOMEM)
			return SMC_CLC_DECL_MEM;/* insufficient memory*/
		return SMC_CLC_DECL_INTERR; /* other error */
	}
	ini->ism_gid = pclc_smcd->gid;
	rc = smc_conn_create(new_smc, ini);
	if (rc)
		return rc;

	/* Check if peer can be reached via ISM device */
	if (smc_ism_cantalk(new_smc->conn.lgr->peer_gid,
			    new_smc->conn.lgr->vlan_id,
			    new_smc->conn.lgr->smcd)) {
		if (*local_contact == SMC_FIRST_CONTACT)
		if (ini->cln_first_contact == SMC_FIRST_CONTACT)
			smc_lgr_forget(new_smc->conn.lgr);
		smc_conn_free(&new_smc->conn);
		return SMC_CLC_DECL_CNFERR;
		return SMC_CLC_DECL_SMCDNOTALK;
	}

	/* Create send and receive buffers */
	if (smc_buf_create(new_smc, true)) {
		if (*local_contact == SMC_FIRST_CONTACT)
		if (ini->cln_first_contact == SMC_FIRST_CONTACT)
			smc_lgr_forget(new_smc->conn.lgr);
		smc_conn_free(&new_smc->conn);
		return SMC_CLC_DECL_MEM;
@@ -1227,15 +1215,10 @@ static void smc_listen_work(struct work_struct *work)
	struct socket *newclcsock = new_smc->clcsock;
	struct smc_clc_msg_accept_confirm cclc;
	struct smc_clc_msg_proposal *pclc;
	struct smc_ib_device *ibdev;
	struct smc_init_info ini = {0};
	bool ism_supported = false;
	struct smcd_dev *ismdev;
	u8 buf[SMC_CLC_MAX_LEN];
	int local_contact = 0;
	unsigned short vlan;
	int reason_code = 0;
	int rc = 0;
	u8 ibport;

	if (new_smc->use_fallback) {
		smc_listen_out_connected(new_smc);
@@ -1254,17 +1237,26 @@ static void smc_listen_work(struct work_struct *work)
	 * wait for and receive SMC Proposal CLC message
	 */
	pclc = (struct smc_clc_msg_proposal *)&buf;
	reason_code = smc_clc_wait_msg(new_smc, pclc, SMC_CLC_MAX_LEN,
	rc = smc_clc_wait_msg(new_smc, pclc, SMC_CLC_MAX_LEN,
			      SMC_CLC_PROPOSAL, CLC_WAIT_TIME);
	if (reason_code) {
		smc_listen_decline(new_smc, reason_code, 0);
		return;
	}
	if (rc)
		goto out_decl;

	/* IPSec connections opt out of SMC-R optimizations */
	if (using_ipsec(new_smc)) {
		smc_listen_decline(new_smc, SMC_CLC_DECL_IPSEC, 0);
		return;
		rc = SMC_CLC_DECL_IPSEC;
		goto out_decl;
	}

	/* check for matching IP prefix and subnet length */
	rc = smc_listen_prfx_check(new_smc, pclc);
	if (rc)
		goto out_decl;

	/* get vlan id from IP device */
	if (smc_vlan_by_tcpsk(new_smc->clcsock, &ini)) {
		rc = SMC_CLC_DECL_GETVLANERR;
		goto out_decl;
	}

	mutex_lock(&smc_server_lgr_pending);
@@ -1273,59 +1265,73 @@ static void smc_listen_work(struct work_struct *work)
	smc_tx_init(new_smc);

	/* check if ISM is available */
	if ((pclc->hdr.path == SMC_TYPE_D || pclc->hdr.path == SMC_TYPE_B) &&
	    !smc_check_ism(new_smc, &ismdev) &&
	    !smc_listen_ism_init(new_smc, pclc, ismdev, &local_contact)) {
	if (pclc->hdr.path == SMC_TYPE_D || pclc->hdr.path == SMC_TYPE_B) {
		ini.is_smcd = true; /* prepare ISM check */
		rc = smc_find_ism_device(new_smc, &ini);
		if (!rc)
			rc = smc_listen_ism_init(new_smc, pclc, &ini);
		if (!rc)
			ism_supported = true;
		else if (pclc->hdr.path == SMC_TYPE_D)
			goto out_unlock; /* skip RDMA and decline */
	}

	/* check if RDMA is available */
	if (!ism_supported &&
	    ((pclc->hdr.path != SMC_TYPE_R && pclc->hdr.path != SMC_TYPE_B) ||
	     smc_vlan_by_tcpsk(new_smc->clcsock, &vlan) ||
	     smc_check_rdma(new_smc, &ibdev, &ibport, vlan, NULL) ||
	     smc_listen_rdma_check(new_smc, pclc) ||
	     smc_listen_rdma_init(new_smc, pclc, ibdev, ibport,
				  &local_contact) ||
	     smc_listen_rdma_reg(new_smc, local_contact))) {
		/* SMC not supported, decline */
		mutex_unlock(&smc_server_lgr_pending);
		smc_listen_decline(new_smc, SMC_CLC_DECL_MODEUNSUPP,
				   local_contact);
		return;
	if (!ism_supported) { /* SMC_TYPE_R or SMC_TYPE_B */
		/* prepare RDMA check */
		memset(&ini, 0, sizeof(ini));
		ini.is_smcd = false;
		ini.ib_lcl = &pclc->lcl;
		rc = smc_find_rdma_device(new_smc, &ini);
		if (rc) {
			/* no RDMA device found */
			if (pclc->hdr.path == SMC_TYPE_B)
				/* neither ISM nor RDMA device found */
				rc = SMC_CLC_DECL_NOSMCDEV;
			goto out_unlock;
		}
		rc = smc_listen_rdma_init(new_smc, &ini);
		if (rc)
			goto out_unlock;
		rc = smc_listen_rdma_reg(new_smc, ini.cln_first_contact);
		if (rc)
			goto out_unlock;
	}

	/* send SMC Accept CLC message */
	rc = smc_clc_send_accept(new_smc, local_contact);
	if (rc) {
		mutex_unlock(&smc_server_lgr_pending);
		smc_listen_decline(new_smc, rc, local_contact);
		return;
	}
	rc = smc_clc_send_accept(new_smc, ini.cln_first_contact);
	if (rc)
		goto out_unlock;

	/* SMC-D does not need this lock any more */
	if (ism_supported)
		mutex_unlock(&smc_server_lgr_pending);

	/* receive SMC Confirm CLC message */
	reason_code = smc_clc_wait_msg(new_smc, &cclc, sizeof(cclc),
	rc = smc_clc_wait_msg(new_smc, &cclc, sizeof(cclc),
			      SMC_CLC_CONFIRM, CLC_WAIT_TIME);
	if (reason_code) {
	if (rc) {
		if (!ism_supported)
			mutex_unlock(&smc_server_lgr_pending);
		smc_listen_decline(new_smc, reason_code, local_contact);
		return;
			goto out_unlock;
		goto out_decl;
	}

	/* finish worker */
	if (!ism_supported) {
		rc = smc_listen_rdma_finish(new_smc, &cclc, local_contact);
		rc = smc_listen_rdma_finish(new_smc, &cclc,
					    ini.cln_first_contact);
		mutex_unlock(&smc_server_lgr_pending);
		if (rc)
			return;
	}
	smc_conn_save_peer_info(new_smc, &cclc);
	smc_listen_out_connected(new_smc);
	return;

out_unlock:
	mutex_unlock(&smc_server_lgr_pending);
out_decl:
	smc_listen_decline(new_smc, rc, ini.cln_first_contact);
}

static void smc_tcp_listen_work(struct work_struct *work)
@@ -1571,8 +1577,8 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
			     poll_table *wait)
{
	struct sock *sk = sock->sk;
	__poll_t mask = 0;
	struct smc_sock *smc;
	__poll_t mask = 0;

	if (!sk)
		return EPOLLNVAL;
@@ -1582,8 +1588,6 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
		/* delegate to CLC child sock */
		mask = smc->clcsock->ops->poll(file, smc->clcsock, wait);
		sk->sk_err = smc->clcsock->sk->sk_err;
		if (sk->sk_err)
			mask |= EPOLLERR;
	} else {
		if (sk->sk_state != SMC_CLOSED)
			sock_poll_wait(file, sock, wait);
@@ -1594,9 +1598,14 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
			mask |= EPOLLHUP;
		if (sk->sk_state == SMC_LISTEN) {
			/* woken up by sk_data_ready in smc_listen_work() */
			mask = smc_accept_poll(sk);
			mask |= smc_accept_poll(sk);
		} else if (smc->use_fallback) { /* as result of connect_work()*/
			mask |= smc->clcsock->ops->poll(file, smc->clcsock,
							   wait);
			sk->sk_err = smc->clcsock->sk->sk_err;
		} else {
			if (atomic_read(&smc->conn.sndbuf_space) ||
			if ((sk->sk_state != SMC_INIT &&
			     atomic_read(&smc->conn.sndbuf_space)) ||
			    sk->sk_shutdown & SEND_SHUTDOWN) {
				mask |= EPOLLOUT | EPOLLWRNORM;
			} else {
+4 −7
Original line number Diff line number Diff line
@@ -190,18 +190,11 @@ struct smc_connection {
	u64			peer_token;	/* SMC-D token of peer */
};

struct smc_connect_info {
	int			flags;
	int			alen;
	struct sockaddr		addr;
};

struct smc_sock {				/* smc sock container */
	struct sock		sk;
	struct socket		*clcsock;	/* internal tcp socket */
	struct smc_connection	conn;		/* smc connection */
	struct smc_sock		*listen_smc;	/* listen parent */
	struct smc_connect_info *connect_info;	/* connect address & flags */
	struct work_struct	connect_work;	/* handle non-blocking connect*/
	struct work_struct	tcp_listen_work;/* handle tcp socket accepts */
	struct work_struct	smc_listen_work;/* prepare new accept socket */
@@ -219,6 +212,10 @@ struct smc_sock { /* smc sock container */
						 * started, waiting for unsent
						 * data to be sent
						 */
	u8			connect_nonblock : 1;
						/* non-blocking connect in
						 * flight
						 */
	struct mutex            clcsock_release_lock;
						/* protects clcsock of a listen
						 * socket
+5 −5
Original line number Diff line number Diff line
@@ -385,8 +385,7 @@ int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info)

/* send CLC PROPOSAL message across internal TCP socket */
int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
			  struct smc_ib_device *ibdev, u8 ibport, u8 gid[],
			  struct smcd_dev *ismdev)
			  struct smc_init_info *ini)
{
	struct smc_clc_ipv6_prefix ipv6_prfx[SMC_CLC_MAX_V6_PREFIX];
	struct smc_clc_msg_proposal_prefix pclc_prfx;
@@ -416,8 +415,9 @@ int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
		/* add SMC-R specifics */
		memcpy(pclc.lcl.id_for_peer, local_systemid,
		       sizeof(local_systemid));
		memcpy(&pclc.lcl.gid, gid, SMC_GID_SIZE);
		memcpy(&pclc.lcl.mac, &ibdev->mac[ibport - 1], ETH_ALEN);
		memcpy(&pclc.lcl.gid, ini->ib_gid, SMC_GID_SIZE);
		memcpy(&pclc.lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1],
		       ETH_ALEN);
		pclc.iparea_offset = htons(0);
	}
	if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) {
@@ -425,7 +425,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
		memset(&pclc_smcd, 0, sizeof(pclc_smcd));
		plen += sizeof(pclc_smcd);
		pclc.iparea_offset = htons(SMC_CLC_PROPOSAL_MAX_OFFSET);
		pclc_smcd.gid = ismdev->local_gid;
		pclc_smcd.gid = ini->ism_dev->local_gid;
	}
	pclc.hdr.length = htons(plen);

+13 −7
Original line number Diff line number Diff line
@@ -34,16 +34,22 @@
#define SMC_CLC_DECL_CNFERR	0x03000000  /* configuration error            */
#define SMC_CLC_DECL_PEERNOSMC	0x03010000  /* peer did not indicate SMC      */
#define SMC_CLC_DECL_IPSEC	0x03020000  /* IPsec usage		      */
#define SMC_CLC_DECL_NOSMCDEV	0x03030000  /* no SMC device found	      */
#define SMC_CLC_DECL_NOSMCDEV	0x03030000  /* no SMC device found (R or D)   */
#define SMC_CLC_DECL_NOSMCDDEV	0x03030001  /* no SMC-D device found	      */
#define SMC_CLC_DECL_NOSMCRDEV	0x03030002  /* no SMC-R device found	      */
#define SMC_CLC_DECL_SMCDNOTALK	0x03030003  /* SMC-D dev can't talk to peer   */
#define SMC_CLC_DECL_MODEUNSUPP	0x03040000  /* smc modes do not match (R or D)*/
#define SMC_CLC_DECL_RMBE_EC	0x03050000  /* peer has eyecatcher in RMBE    */
#define SMC_CLC_DECL_OPTUNSUPP	0x03060000  /* fastopen sockopt not supported */
#define SMC_CLC_DECL_DIFFPREFIX	0x03070000  /* IP prefix / subnet mismatch    */
#define SMC_CLC_DECL_GETVLANERR	0x03080000  /* err to get vlan id of ip device*/
#define SMC_CLC_DECL_ISMVLANERR	0x03090000  /* err to reg vlan id on ism dev  */
#define SMC_CLC_DECL_SYNCERR	0x04000000  /* synchronization error          */
#define SMC_CLC_DECL_PEERDECL	0x05000000  /* peer declined during handshake */
#define SMC_CLC_DECL_INTERR	0x99990000  /* internal error                 */
#define SMC_CLC_DECL_ERR_RTOK	0x99990001  /*	 rtoken handling failed       */
#define SMC_CLC_DECL_ERR_RDYLNK	0x99990002  /*	 ib ready link failed	      */
#define SMC_CLC_DECL_ERR_REGRMB	0x99990003  /*	 reg rmb failed		      */
#define SMC_CLC_DECL_INTERR	0x09990000  /* internal error		      */
#define SMC_CLC_DECL_ERR_RTOK	0x09990001  /*	 rtoken handling failed       */
#define SMC_CLC_DECL_ERR_RDYLNK	0x09990002  /*	 ib ready link failed	      */
#define SMC_CLC_DECL_ERR_REGRMB	0x09990003  /*	 reg rmb failed		      */

struct smc_clc_msg_hdr {	/* header1 of clc messages */
	u8 eyecatcher[4];	/* eye catcher */
@@ -179,6 +185,7 @@ smc_get_clc_msg_smcd(struct smc_clc_msg_proposal *prop)
}

struct smcd_dev;
struct smc_init_info;

int smc_clc_prfx_match(struct socket *clcsock,
		       struct smc_clc_msg_proposal_prefix *prop);
@@ -186,8 +193,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
		     u8 expected_type, unsigned long timeout);
int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info);
int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
			  struct smc_ib_device *smcibdev, u8 ibport, u8 gid[],
			  struct smcd_dev *ismdev);
			  struct smc_init_info *ini);
int smc_clc_send_confirm(struct smc_sock *smc);
int smc_clc_send_accept(struct smc_sock *smc, int srv_first_contact);

+46 −47

File changed.

Preview size limit exceeded, changes collapsed.

Loading