summaryrefslogtreecommitdiff
path: root/net/smc/af_smc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/smc/af_smc.c')
-rw-r--r--net/smc/af_smc.c100
1 files changed, 61 insertions, 39 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 5dd4faaf7d6e..47340b3b514f 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -45,6 +45,7 @@
#include "smc_ib.h"
#include "smc_ism.h"
#include "smc_pnet.h"
+#include "smc_netlink.h"
#include "smc_tx.h"
#include "smc_rx.h"
#include "smc_close.h"
@@ -552,8 +553,7 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code,
return smc_connect_fallback(smc, reason_code);
}
-/* abort connecting */
-static void smc_connect_abort(struct smc_sock *smc, int local_first)
+static void smc_conn_abort(struct smc_sock *smc, int local_first)
{
if (local_first)
smc_lgr_cleanup_early(&smc->conn);
@@ -669,7 +669,7 @@ static int smc_find_proposal_devices(struct smc_sock *smc,
ini->smc_type_v1 = SMC_TYPE_N;
} /* else RDMA is supported for this connection */
}
- if (smc_ism_v2_capable && smc_find_ism_v2_device_clnt(smc, ini))
+ if (smc_ism_is_v2_capable() && smc_find_ism_v2_device_clnt(smc, ini))
ini->smc_type_v2 = SMC_TYPE_N;
/* if neither ISM nor RDMA are supported, fallback */
@@ -814,7 +814,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
return 0;
connect_abort:
- smc_connect_abort(smc, ini->first_contact_local);
+ smc_conn_abort(smc, ini->first_contact_local);
mutex_unlock(&smc_client_lgr_pending);
smc->connect_nonblock = 0;
@@ -893,7 +893,7 @@ static int smc_connect_ism(struct smc_sock *smc,
return 0;
connect_abort:
- smc_connect_abort(smc, ini->first_contact_local);
+ smc_conn_abort(smc, ini->first_contact_local);
mutex_unlock(&smc_server_lgr_pending);
smc->connect_nonblock = 0;
@@ -921,7 +921,7 @@ static int smc_connect_check_aclc(struct smc_init_info *ini,
/* perform steps before actually connecting */
static int __smc_connect(struct smc_sock *smc)
{
- u8 version = smc_ism_v2_capable ? SMC_V2 : SMC_V1;
+ u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1;
struct smc_clc_msg_accept_confirm_v2 *aclc2;
struct smc_clc_msg_accept_confirm *aclc;
struct smc_init_info *ini = NULL;
@@ -946,9 +946,9 @@ static int __smc_connect(struct smc_sock *smc)
version);
ini->smcd_version = SMC_V1;
- ini->smcd_version |= smc_ism_v2_capable ? SMC_V2 : 0;
+ ini->smcd_version |= smc_ism_is_v2_capable() ? SMC_V2 : 0;
ini->smc_type_v1 = SMC_TYPE_B;
- ini->smc_type_v2 = smc_ism_v2_capable ? SMC_TYPE_D : SMC_TYPE_N;
+ ini->smc_type_v2 = smc_ism_is_v2_capable() ? SMC_TYPE_D : SMC_TYPE_N;
/* get vlan id from IP device */
if (smc_vlan_by_tcpsk(smc->clcsock, ini)) {
@@ -1321,10 +1321,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
int local_first, u8 version)
{
/* RDMA setup failed, switch back to TCP */
- if (local_first)
- smc_lgr_cleanup_early(&new_smc->conn);
- else
- smc_conn_free(&new_smc->conn);
+ smc_conn_abort(new_smc, local_first);
if (reason_code < 0) { /* error, no fallback possible */
smc_listen_out_err(new_smc);
return;
@@ -1347,6 +1344,7 @@ static int smc_listen_v2_check(struct smc_sock *new_smc,
{
struct smc_clc_smcd_v2_extension *pclc_smcd_v2_ext;
struct smc_clc_v2_extension *pclc_v2_ext;
+ int rc = SMC_CLC_DECL_PEERNOSMC;
ini->smc_type_v1 = pclc->hdr.typev1;
ini->smc_type_v2 = pclc->hdr.typev2;
@@ -1354,29 +1352,30 @@ static int smc_listen_v2_check(struct smc_sock *new_smc,
if (pclc->hdr.version > SMC_V1)
ini->smcd_version |=
ini->smc_type_v2 != SMC_TYPE_N ? SMC_V2 : 0;
- if (!smc_ism_v2_capable) {
+ if (!(ini->smcd_version & SMC_V2)) {
+ rc = SMC_CLC_DECL_PEERNOSMC;
+ goto out;
+ }
+ if (!smc_ism_is_v2_capable()) {
ini->smcd_version &= ~SMC_V2;
+ rc = SMC_CLC_DECL_NOISM2SUPP;
goto out;
}
pclc_v2_ext = smc_get_clc_v2_ext(pclc);
if (!pclc_v2_ext) {
ini->smcd_version &= ~SMC_V2;
+ rc = SMC_CLC_DECL_NOV2EXT;
goto out;
}
pclc_smcd_v2_ext = smc_get_clc_smcd_v2_ext(pclc_v2_ext);
- if (!pclc_smcd_v2_ext)
+ if (!pclc_smcd_v2_ext) {
ini->smcd_version &= ~SMC_V2;
+ rc = SMC_CLC_DECL_NOV2DEXT;
+ }
out:
- if (!ini->smcd_version) {
- if (pclc->hdr.typev1 == SMC_TYPE_B ||
- pclc->hdr.typev2 == SMC_TYPE_B)
- return SMC_CLC_DECL_NOSMCDEV;
- if (pclc->hdr.typev1 == SMC_TYPE_D ||
- pclc->hdr.typev2 == SMC_TYPE_D)
- return SMC_CLC_DECL_NOSMCDDEV;
- return SMC_CLC_DECL_NOSMCRDEV;
- }
+ if (!ini->smcd_version)
+ return rc;
return 0;
}
@@ -1428,10 +1427,7 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
/* Create send and receive buffers */
rc = smc_buf_create(new_smc, true);
if (rc) {
- if (ini->first_contact_local)
- smc_lgr_cleanup_early(&new_smc->conn);
- else
- smc_conn_free(&new_smc->conn);
+ smc_conn_abort(new_smc, ini->first_contact_local);
return (rc == -ENOSPC) ? SMC_CLC_DECL_MAX_DMB :
SMC_CLC_DECL_MEM;
}
@@ -1474,6 +1470,12 @@ static void smc_check_ism_v2_match(struct smc_init_info *ini,
}
}
+static void smc_find_ism_store_rc(u32 rc, struct smc_init_info *ini)
+{
+ if (!ini->rc)
+ ini->rc = rc;
+}
+
static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
struct smc_clc_msg_proposal *pclc,
struct smc_init_info *ini)
@@ -1484,7 +1486,7 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
unsigned int matches = 0;
u8 smcd_version;
u8 *eid = NULL;
- int i;
+ int i, rc;
if (!(ini->smcd_version & SMC_V2) || !smcd_indicated(ini->smc_type_v2))
goto not_found;
@@ -1493,8 +1495,10 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
smc_v2_ext = smc_get_clc_v2_ext(pclc);
smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);
if (!smcd_v2_ext ||
- !smc_v2_ext->hdr.flag.seid) /* no system EID support for SMCD */
+ !smc_v2_ext->hdr.flag.seid) { /* no system EID support for SMCD */
+ smc_find_ism_store_rc(SMC_CLC_DECL_NOSEID, ini);
goto not_found;
+ }
mutex_lock(&smcd_dev_list.mutex);
if (pclc_smcd->ism.chid)
@@ -1526,9 +1530,12 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
ini->smcd_version = SMC_V2;
ini->is_smcd = true;
ini->ism_selected = i;
- if (smc_listen_ism_init(new_smc, ini))
+ rc = smc_listen_ism_init(new_smc, ini);
+ if (rc) {
+ smc_find_ism_store_rc(rc, ini);
/* try next active ISM device */
continue;
+ }
return; /* matching and usable V2 ISM device found */
}
/* no V2 ISM device could be initialized */
@@ -1545,19 +1552,23 @@ static void smc_find_ism_v1_device_serv(struct smc_sock *new_smc,
struct smc_init_info *ini)
{
struct smc_clc_msg_smcd *pclc_smcd = smc_get_clc_msg_smcd(pclc);
+ int rc = 0;
/* check if ISM V1 is available */
if (!(ini->smcd_version & SMC_V1) || !smcd_indicated(ini->smc_type_v1))
goto not_found;
ini->is_smcd = true; /* prepare ISM check */
ini->ism_peer_gid[0] = ntohll(pclc_smcd->ism.gid);
- if (smc_find_ism_device(new_smc, ini))
+ rc = smc_find_ism_device(new_smc, ini);
+ if (rc)
goto not_found;
ini->ism_selected = 0;
- if (!smc_listen_ism_init(new_smc, ini))
+ rc = smc_listen_ism_init(new_smc, ini);
+ if (!rc)
return; /* V1 ISM device found */
not_found:
+ smc_find_ism_store_rc(rc, ini);
ini->ism_dev[0] = NULL;
ini->is_smcd = false;
}
@@ -1614,16 +1625,16 @@ static int smc_listen_find_device(struct smc_sock *new_smc,
return 0;
if (!(ini->smcd_version & SMC_V1))
- return SMC_CLC_DECL_NOSMCDEV;
+ return ini->rc ?: SMC_CLC_DECL_NOSMCD2DEV;
/* check for matching IP prefix and subnet length */
rc = smc_listen_prfx_check(new_smc, pclc);
if (rc)
- return rc;
+ return ini->rc ?: rc;
/* get vlan id from IP device */
if (smc_vlan_by_tcpsk(new_smc->clcsock, ini))
- return SMC_CLC_DECL_GETVLANERR;
+ return ini->rc ?: SMC_CLC_DECL_GETVLANERR;
/* check for ISM device matching V1 proposed device */
smc_find_ism_v1_device_serv(new_smc, pclc, ini);
@@ -1631,10 +1642,14 @@ static int smc_listen_find_device(struct smc_sock *new_smc,
return 0;
if (pclc->hdr.typev1 == SMC_TYPE_D)
- return SMC_CLC_DECL_NOSMCDDEV; /* skip RDMA and decline */
+ /* skip RDMA and decline */
+ return ini->rc ?: SMC_CLC_DECL_NOSMCDDEV;
/* check if RDMA is available */
- return smc_find_rdma_v1_device_serv(new_smc, pclc, ini);
+ rc = smc_find_rdma_v1_device_serv(new_smc, pclc, ini);
+ smc_find_ism_store_rc(rc, ini);
+
+ return (!rc) ? 0 : ini->rc;
}
/* listen worker: finish RDMA setup */
@@ -1667,7 +1682,7 @@ static void smc_listen_work(struct work_struct *work)
{
struct smc_sock *new_smc = container_of(work, struct smc_sock,
smc_listen_work);
- u8 version = smc_ism_v2_capable ? SMC_V2 : SMC_V1;
+ u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1;
struct socket *newclcsock = new_smc->clcsock;
struct smc_clc_msg_accept_confirm *cclc;
struct smc_clc_msg_proposal_area *buf;
@@ -2481,10 +2496,14 @@ static int __init smc_init(void)
smc_ism_init();
smc_clc_init();
- rc = smc_pnet_init();
+ rc = smc_nl_init();
if (rc)
goto out_pernet_subsys;
+ rc = smc_pnet_init();
+ if (rc)
+ goto out_nl;
+
rc = -ENOMEM;
smc_hs_wq = alloc_workqueue("smc_hs_wq", 0, 0);
if (!smc_hs_wq)
@@ -2555,6 +2574,8 @@ out_alloc_hs_wq:
destroy_workqueue(smc_hs_wq);
out_pnet:
smc_pnet_exit();
+out_nl:
+ smc_nl_exit();
out_pernet_subsys:
unregister_pernet_subsys(&smc_net_ops);
@@ -2572,6 +2593,7 @@ static void __exit smc_exit(void)
proto_unregister(&smc_proto6);
proto_unregister(&smc_proto);
smc_pnet_exit();
+ smc_nl_exit();
unregister_pernet_subsys(&smc_net_ops);
rcu_barrier();
}