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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e0a092ebeb
341
net/smc/af_smc.c
341
net/smc/af_smc.c
|
@ -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 @@ out:
|
|||
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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -195,10 +195,7 @@ static void smc_lgr_free_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
/* create a new SMC link group */
|
||||
static int smc_lgr_create(struct smc_sock *smc, bool is_smcd,
|
||||
struct smc_ib_device *smcibdev, u8 ibport,
|
||||
char *peer_systemid, unsigned short vlan_id,
|
||||
struct smcd_dev *smcismdev, u64 peer_gid)
|
||||
static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
|
||||
{
|
||||
struct smc_link_group *lgr;
|
||||
struct smc_link *lnk;
|
||||
|
@ -206,20 +203,21 @@ static int smc_lgr_create(struct smc_sock *smc, bool is_smcd,
|
|||
int rc = 0;
|
||||
int i;
|
||||
|
||||
if (is_smcd && vlan_id) {
|
||||
rc = smc_ism_get_vlan(smcismdev, vlan_id);
|
||||
if (rc)
|
||||
if (ini->is_smcd && ini->vlan_id) {
|
||||
if (smc_ism_get_vlan(ini->ism_dev, ini->vlan_id)) {
|
||||
rc = SMC_CLC_DECL_ISMVLANERR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
lgr = kzalloc(sizeof(*lgr), GFP_KERNEL);
|
||||
if (!lgr) {
|
||||
rc = -ENOMEM;
|
||||
rc = SMC_CLC_DECL_MEM;
|
||||
goto out;
|
||||
}
|
||||
lgr->is_smcd = is_smcd;
|
||||
lgr->is_smcd = ini->is_smcd;
|
||||
lgr->sync_err = 0;
|
||||
lgr->vlan_id = vlan_id;
|
||||
lgr->vlan_id = ini->vlan_id;
|
||||
rwlock_init(&lgr->sndbufs_lock);
|
||||
rwlock_init(&lgr->rmbs_lock);
|
||||
rwlock_init(&lgr->conns_lock);
|
||||
|
@ -231,29 +229,32 @@ static int smc_lgr_create(struct smc_sock *smc, bool is_smcd,
|
|||
memcpy(&lgr->id, (u8 *)&smc_lgr_list.num, SMC_LGR_ID_SIZE);
|
||||
INIT_DELAYED_WORK(&lgr->free_work, smc_lgr_free_work);
|
||||
lgr->conns_all = RB_ROOT;
|
||||
if (is_smcd) {
|
||||
if (ini->is_smcd) {
|
||||
/* SMC-D specific settings */
|
||||
lgr->peer_gid = peer_gid;
|
||||
lgr->smcd = smcismdev;
|
||||
lgr->peer_gid = ini->ism_gid;
|
||||
lgr->smcd = ini->ism_dev;
|
||||
} else {
|
||||
/* SMC-R specific settings */
|
||||
lgr->role = smc->listen_smc ? SMC_SERV : SMC_CLNT;
|
||||
memcpy(lgr->peer_systemid, peer_systemid, SMC_SYSTEMID_LEN);
|
||||
memcpy(lgr->peer_systemid, ini->ib_lcl->id_for_peer,
|
||||
SMC_SYSTEMID_LEN);
|
||||
|
||||
lnk = &lgr->lnk[SMC_SINGLE_LINK];
|
||||
/* initialize link */
|
||||
lnk->state = SMC_LNK_ACTIVATING;
|
||||
lnk->link_id = SMC_SINGLE_LINK;
|
||||
lnk->smcibdev = smcibdev;
|
||||
lnk->ibport = ibport;
|
||||
lnk->path_mtu = smcibdev->pattr[ibport - 1].active_mtu;
|
||||
if (!smcibdev->initialized)
|
||||
smc_ib_setup_per_ibdev(smcibdev);
|
||||
lnk->smcibdev = ini->ib_dev;
|
||||
lnk->ibport = ini->ib_port;
|
||||
lnk->path_mtu =
|
||||
ini->ib_dev->pattr[ini->ib_port - 1].active_mtu;
|
||||
if (!ini->ib_dev->initialized)
|
||||
smc_ib_setup_per_ibdev(ini->ib_dev);
|
||||
get_random_bytes(rndvec, sizeof(rndvec));
|
||||
lnk->psn_initial = rndvec[0] + (rndvec[1] << 8) +
|
||||
(rndvec[2] << 16);
|
||||
rc = smc_ib_determine_gid(lnk->smcibdev, lnk->ibport,
|
||||
vlan_id, lnk->gid, &lnk->sgid_index);
|
||||
ini->vlan_id, lnk->gid,
|
||||
&lnk->sgid_index);
|
||||
if (rc)
|
||||
goto free_lgr;
|
||||
rc = smc_llc_link_init(lnk);
|
||||
|
@ -289,6 +290,12 @@ clear_llc_lnk:
|
|||
free_lgr:
|
||||
kfree(lgr);
|
||||
out:
|
||||
if (rc < 0) {
|
||||
if (rc == -ENOMEM)
|
||||
rc = SMC_CLC_DECL_MEM;
|
||||
else
|
||||
rc = SMC_CLC_DECL_INTERR;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -528,13 +535,13 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
|
|||
/* Determine vlan of internal TCP socket.
|
||||
* @vlan_id: address to store the determined vlan id into
|
||||
*/
|
||||
int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id)
|
||||
int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini)
|
||||
{
|
||||
struct dst_entry *dst = sk_dst_get(clcsock->sk);
|
||||
struct net_device *ndev;
|
||||
int i, nest_lvl, rc = 0;
|
||||
|
||||
*vlan_id = 0;
|
||||
ini->vlan_id = 0;
|
||||
if (!dst) {
|
||||
rc = -ENOTCONN;
|
||||
goto out;
|
||||
|
@ -546,7 +553,7 @@ int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id)
|
|||
|
||||
ndev = dst->dev;
|
||||
if (is_vlan_dev(ndev)) {
|
||||
*vlan_id = vlan_dev_vlan_id(ndev);
|
||||
ini->vlan_id = vlan_dev_vlan_id(ndev);
|
||||
goto out_rel;
|
||||
}
|
||||
|
||||
|
@ -560,7 +567,7 @@ int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id)
|
|||
lower = lower->next;
|
||||
ndev = (struct net_device *)netdev_lower_get_next(ndev, &lower);
|
||||
if (is_vlan_dev(ndev)) {
|
||||
*vlan_id = vlan_dev_vlan_id(ndev);
|
||||
ini->vlan_id = vlan_dev_vlan_id(ndev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -594,24 +601,16 @@ static bool smcd_lgr_match(struct smc_link_group *lgr,
|
|||
}
|
||||
|
||||
/* create a new SMC connection (and a new link group if necessary) */
|
||||
int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
|
||||
struct smc_ib_device *smcibdev, u8 ibport, u32 clcqpn,
|
||||
struct smc_clc_msg_local *lcl, struct smcd_dev *smcd,
|
||||
u64 peer_gid)
|
||||
int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
|
||||
{
|
||||
struct smc_connection *conn = &smc->conn;
|
||||
int local_contact = SMC_FIRST_CONTACT;
|
||||
struct smc_link_group *lgr;
|
||||
unsigned short vlan_id;
|
||||
enum smc_lgr_role role;
|
||||
int rc = 0;
|
||||
|
||||
ini->cln_first_contact = SMC_FIRST_CONTACT;
|
||||
role = smc->listen_smc ? SMC_SERV : SMC_CLNT;
|
||||
rc = smc_vlan_by_tcpsk(smc->clcsock, &vlan_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if ((role == SMC_CLNT) && srv_first_contact)
|
||||
if (role == SMC_CLNT && ini->srv_first_contact)
|
||||
/* create new link group as well */
|
||||
goto create;
|
||||
|
||||
|
@ -619,14 +618,15 @@ int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
|
|||
spin_lock_bh(&smc_lgr_list.lock);
|
||||
list_for_each_entry(lgr, &smc_lgr_list.list, list) {
|
||||
write_lock_bh(&lgr->conns_lock);
|
||||
if ((is_smcd ? smcd_lgr_match(lgr, smcd, peer_gid) :
|
||||
smcr_lgr_match(lgr, lcl, role, clcqpn)) &&
|
||||
if ((ini->is_smcd ?
|
||||
smcd_lgr_match(lgr, ini->ism_dev, ini->ism_gid) :
|
||||
smcr_lgr_match(lgr, ini->ib_lcl, role, ini->ib_clcqpn)) &&
|
||||
!lgr->sync_err &&
|
||||
lgr->vlan_id == vlan_id &&
|
||||
lgr->vlan_id == ini->vlan_id &&
|
||||
(role == SMC_CLNT ||
|
||||
lgr->conns_num < SMC_RMBS_PER_LGR_MAX)) {
|
||||
/* link group found */
|
||||
local_contact = SMC_REUSE_CONTACT;
|
||||
ini->cln_first_contact = SMC_REUSE_CONTACT;
|
||||
conn->lgr = lgr;
|
||||
smc_lgr_register_conn(conn); /* add smc conn to lgr */
|
||||
if (delayed_work_pending(&lgr->free_work))
|
||||
|
@ -638,19 +638,18 @@ int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
|
|||
}
|
||||
spin_unlock_bh(&smc_lgr_list.lock);
|
||||
|
||||
if (role == SMC_CLNT && !srv_first_contact &&
|
||||
(local_contact == SMC_FIRST_CONTACT)) {
|
||||
if (role == SMC_CLNT && !ini->srv_first_contact &&
|
||||
ini->cln_first_contact == SMC_FIRST_CONTACT) {
|
||||
/* Server reuses a link group, but Client wants to start
|
||||
* a new one
|
||||
* send out_of_sync decline, reason synchr. error
|
||||
*/
|
||||
return -ENOLINK;
|
||||
return SMC_CLC_DECL_SYNCERR;
|
||||
}
|
||||
|
||||
create:
|
||||
if (local_contact == SMC_FIRST_CONTACT) {
|
||||
rc = smc_lgr_create(smc, is_smcd, smcibdev, ibport,
|
||||
lcl->id_for_peer, vlan_id, smcd, peer_gid);
|
||||
if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
|
||||
rc = smc_lgr_create(smc, ini);
|
||||
if (rc)
|
||||
goto out;
|
||||
smc_lgr_register_conn(conn); /* add smc conn to lgr */
|
||||
|
@ -658,7 +657,7 @@ create:
|
|||
conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
|
||||
conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
|
||||
conn->urg_state = SMC_URG_READ;
|
||||
if (is_smcd) {
|
||||
if (ini->is_smcd) {
|
||||
conn->rx_off = sizeof(struct smcd_cdc_msg);
|
||||
smcd_cdc_rx_init(conn); /* init tasklet for this conn */
|
||||
}
|
||||
|
@ -667,7 +666,7 @@ create:
|
|||
#endif
|
||||
|
||||
out:
|
||||
return rc ? rc : local_contact;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* convert the RMB size into the compressed notation - minimum 16K.
|
||||
|
|
|
@ -229,6 +229,24 @@ struct smc_link_group {
|
|||
};
|
||||
};
|
||||
|
||||
struct smc_clc_msg_local;
|
||||
|
||||
struct smc_init_info {
|
||||
u8 is_smcd;
|
||||
unsigned short vlan_id;
|
||||
int srv_first_contact;
|
||||
int cln_first_contact;
|
||||
/* SMC-R */
|
||||
struct smc_clc_msg_local *ib_lcl;
|
||||
struct smc_ib_device *ib_dev;
|
||||
u8 ib_gid[SMC_GID_SIZE];
|
||||
u8 ib_port;
|
||||
u32 ib_clcqpn;
|
||||
/* SMC-D */
|
||||
u64 ism_gid;
|
||||
struct smcd_dev *ism_dev;
|
||||
};
|
||||
|
||||
/* Find the connection associated with the given alert token in the link group.
|
||||
* To use rbtrees we have to implement our own search core.
|
||||
* Requires @conns_lock
|
||||
|
@ -281,13 +299,10 @@ void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn);
|
|||
void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn);
|
||||
void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn);
|
||||
void smc_rmb_sync_sg_for_device(struct smc_connection *conn);
|
||||
int smc_vlan_by_tcpsk(struct socket *clcsock, unsigned short *vlan_id);
|
||||
int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini);
|
||||
|
||||
void smc_conn_free(struct smc_connection *conn);
|
||||
int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
|
||||
struct smc_ib_device *smcibdev, u8 ibport, u32 clcqpn,
|
||||
struct smc_clc_msg_local *lcl, struct smcd_dev *smcd,
|
||||
u64 peer_gid);
|
||||
int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini);
|
||||
void smcd_conn_free(struct smc_connection *conn);
|
||||
void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr);
|
||||
void smc_core_exit(void);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "smc_pnet.h"
|
||||
#include "smc_ib.h"
|
||||
#include "smc_ism.h"
|
||||
#include "smc_core.h"
|
||||
|
||||
#define SMC_ASCII_BLANK 32
|
||||
|
||||
|
@ -755,8 +756,7 @@ static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
|
|||
* IB device and port
|
||||
*/
|
||||
static void smc_pnet_find_rdma_dev(struct net_device *netdev,
|
||||
struct smc_ib_device **smcibdev,
|
||||
u8 *ibport, unsigned short vlan_id, u8 gid[])
|
||||
struct smc_init_info *ini)
|
||||
{
|
||||
struct smc_ib_device *ibdev;
|
||||
|
||||
|
@ -776,10 +776,10 @@ static void smc_pnet_find_rdma_dev(struct net_device *netdev,
|
|||
dev_put(ndev);
|
||||
if (netdev == ndev &&
|
||||
smc_ib_port_active(ibdev, i) &&
|
||||
!smc_ib_determine_gid(ibdev, i, vlan_id, gid,
|
||||
NULL)) {
|
||||
*smcibdev = ibdev;
|
||||
*ibport = i;
|
||||
!smc_ib_determine_gid(ibdev, i, ini->vlan_id,
|
||||
ini->ib_gid, NULL)) {
|
||||
ini->ib_dev = ibdev;
|
||||
ini->ib_port = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -794,9 +794,7 @@ static void smc_pnet_find_rdma_dev(struct net_device *netdev,
|
|||
* If nothing found, try to use handshake device
|
||||
*/
|
||||
static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
|
||||
struct smc_ib_device **smcibdev,
|
||||
u8 *ibport, unsigned short vlan_id,
|
||||
u8 gid[])
|
||||
struct smc_init_info *ini)
|
||||
{
|
||||
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
|
||||
struct smc_ib_device *ibdev;
|
||||
|
@ -806,7 +804,7 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
|
|||
if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
|
||||
ndev_pnetid) &&
|
||||
smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid)) {
|
||||
smc_pnet_find_rdma_dev(ndev, smcibdev, ibport, vlan_id, gid);
|
||||
smc_pnet_find_rdma_dev(ndev, ini);
|
||||
return; /* pnetid could not be determined */
|
||||
}
|
||||
|
||||
|
@ -817,10 +815,10 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
|
|||
continue;
|
||||
if (smc_pnet_match(ibdev->pnetid[i - 1], ndev_pnetid) &&
|
||||
smc_ib_port_active(ibdev, i) &&
|
||||
!smc_ib_determine_gid(ibdev, i, vlan_id, gid,
|
||||
NULL)) {
|
||||
*smcibdev = ibdev;
|
||||
*ibport = i;
|
||||
!smc_ib_determine_gid(ibdev, i, ini->vlan_id,
|
||||
ini->ib_gid, NULL)) {
|
||||
ini->ib_dev = ibdev;
|
||||
ini->ib_port = i;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -830,7 +828,7 @@ out:
|
|||
}
|
||||
|
||||
static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
|
||||
struct smcd_dev **smcismdev)
|
||||
struct smc_init_info *ini)
|
||||
{
|
||||
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
|
||||
struct smcd_dev *ismdev;
|
||||
|
@ -844,7 +842,7 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
|
|||
spin_lock(&smcd_dev_list.lock);
|
||||
list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
|
||||
if (smc_pnet_match(ismdev->pnetid, ndev_pnetid)) {
|
||||
*smcismdev = ismdev;
|
||||
ini->ism_dev = ismdev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -855,21 +853,18 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
|
|||
* determine ib_device and port belonging to used internal TCP socket
|
||||
* ethernet interface.
|
||||
*/
|
||||
void smc_pnet_find_roce_resource(struct sock *sk,
|
||||
struct smc_ib_device **smcibdev, u8 *ibport,
|
||||
unsigned short vlan_id, u8 gid[])
|
||||
void smc_pnet_find_roce_resource(struct sock *sk, struct smc_init_info *ini)
|
||||
{
|
||||
struct dst_entry *dst = sk_dst_get(sk);
|
||||
|
||||
*smcibdev = NULL;
|
||||
*ibport = 0;
|
||||
|
||||
ini->ib_dev = NULL;
|
||||
ini->ib_port = 0;
|
||||
if (!dst)
|
||||
goto out;
|
||||
if (!dst->dev)
|
||||
goto out_rel;
|
||||
|
||||
smc_pnet_find_roce_by_pnetid(dst->dev, smcibdev, ibport, vlan_id, gid);
|
||||
smc_pnet_find_roce_by_pnetid(dst->dev, ini);
|
||||
|
||||
out_rel:
|
||||
dst_release(dst);
|
||||
|
@ -877,17 +872,17 @@ out:
|
|||
return;
|
||||
}
|
||||
|
||||
void smc_pnet_find_ism_resource(struct sock *sk, struct smcd_dev **smcismdev)
|
||||
void smc_pnet_find_ism_resource(struct sock *sk, struct smc_init_info *ini)
|
||||
{
|
||||
struct dst_entry *dst = sk_dst_get(sk);
|
||||
|
||||
*smcismdev = NULL;
|
||||
ini->ism_dev = NULL;
|
||||
if (!dst)
|
||||
goto out;
|
||||
if (!dst->dev)
|
||||
goto out_rel;
|
||||
|
||||
smc_pnet_find_ism_by_pnetid(dst->dev, smcismdev);
|
||||
smc_pnet_find_ism_by_pnetid(dst->dev, ini);
|
||||
|
||||
out_rel:
|
||||
dst_release(dst);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
struct smc_ib_device;
|
||||
struct smcd_dev;
|
||||
struct smc_init_info;
|
||||
|
||||
/**
|
||||
* struct smc_pnettable - SMC PNET table anchor
|
||||
|
@ -43,9 +44,7 @@ int smc_pnet_init(void) __init;
|
|||
int smc_pnet_net_init(struct net *net);
|
||||
void smc_pnet_exit(void);
|
||||
void smc_pnet_net_exit(struct net *net);
|
||||
void smc_pnet_find_roce_resource(struct sock *sk,
|
||||
struct smc_ib_device **smcibdev, u8 *ibport,
|
||||
unsigned short vlan_id, u8 gid[]);
|
||||
void smc_pnet_find_ism_resource(struct sock *sk, struct smcd_dev **smcismdev);
|
||||
void smc_pnet_find_roce_resource(struct sock *sk, struct smc_init_info *ini);
|
||||
void smc_pnet_find_ism_resource(struct sock *sk, struct smc_init_info *ini);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue