Commit 6bb14e48 authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller

net/smc: dynamic allocation of CLC proposal buffer

Reduce stack size for smc_listen_work() and smc_clc_send_proposal()
by dynamic allocation of the CLC buffer to be received or sent.
Signed-off-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5ac54d87
...@@ -1276,10 +1276,10 @@ static void smc_listen_work(struct work_struct *work) ...@@ -1276,10 +1276,10 @@ static void smc_listen_work(struct work_struct *work)
smc_listen_work); smc_listen_work);
struct socket *newclcsock = new_smc->clcsock; struct socket *newclcsock = new_smc->clcsock;
struct smc_clc_msg_accept_confirm cclc; struct smc_clc_msg_accept_confirm cclc;
struct smc_clc_msg_proposal_area *buf;
struct smc_clc_msg_proposal *pclc; struct smc_clc_msg_proposal *pclc;
struct smc_init_info ini = {0}; struct smc_init_info ini = {0};
bool ism_supported = false; bool ism_supported = false;
u8 buf[SMC_CLC_MAX_LEN];
int rc = 0; int rc = 0;
if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN) if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN)
...@@ -1301,8 +1301,13 @@ static void smc_listen_work(struct work_struct *work) ...@@ -1301,8 +1301,13 @@ static void smc_listen_work(struct work_struct *work)
/* do inband token exchange - /* do inband token exchange -
* wait for and receive SMC Proposal CLC message * wait for and receive SMC Proposal CLC message
*/ */
pclc = (struct smc_clc_msg_proposal *)&buf; buf = kzalloc(sizeof(*buf), GFP_KERNEL);
rc = smc_clc_wait_msg(new_smc, pclc, SMC_CLC_MAX_LEN, if (!buf) {
rc = SMC_CLC_DECL_MEM;
goto out_decl;
}
pclc = (struct smc_clc_msg_proposal *)buf;
rc = smc_clc_wait_msg(new_smc, pclc, sizeof(*buf),
SMC_CLC_PROPOSAL, CLC_WAIT_TIME); SMC_CLC_PROPOSAL, CLC_WAIT_TIME);
if (rc) if (rc)
goto out_decl; goto out_decl;
...@@ -1382,6 +1387,7 @@ static void smc_listen_work(struct work_struct *work) ...@@ -1382,6 +1387,7 @@ static void smc_listen_work(struct work_struct *work)
} }
/* finish worker */ /* finish worker */
kfree(buf);
if (!ism_supported) { if (!ism_supported) {
rc = smc_listen_rdma_finish(new_smc, &cclc, rc = smc_listen_rdma_finish(new_smc, &cclc,
ini.first_contact_local); ini.first_contact_local);
...@@ -1397,6 +1403,7 @@ static void smc_listen_work(struct work_struct *work) ...@@ -1397,6 +1403,7 @@ static void smc_listen_work(struct work_struct *work)
mutex_unlock(&smc_server_lgr_pending); mutex_unlock(&smc_server_lgr_pending);
out_decl: out_decl:
smc_listen_decline(new_smc, rc, ini.first_contact_local); smc_listen_decline(new_smc, rc, ini.first_contact_local);
kfree(buf);
} }
static void smc_tcp_listen_work(struct work_struct *work) static void smc_tcp_listen_work(struct work_struct *work)
......
...@@ -153,7 +153,6 @@ static int smc_clc_prfx_set(struct socket *clcsock, ...@@ -153,7 +153,6 @@ static int smc_clc_prfx_set(struct socket *clcsock,
struct sockaddr_in *addr; struct sockaddr_in *addr;
int rc = -ENOENT; int rc = -ENOENT;
memset(prop, 0, sizeof(*prop));
if (!dst) { if (!dst) {
rc = -ENOTCONN; rc = -ENOTCONN;
goto out; goto out;
...@@ -412,76 +411,89 @@ int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info) ...@@ -412,76 +411,89 @@ 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, int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
struct smc_init_info *ini) 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;
struct smc_clc_msg_proposal_prefix pclc_prfx; struct smc_clc_msg_proposal *pclc_base;
struct smc_clc_msg_smcd pclc_smcd; struct smc_clc_msg_proposal_area *pclc;
struct smc_clc_msg_proposal pclc; struct smc_clc_ipv6_prefix *ipv6_prfx;
struct smc_clc_msg_trail trl; struct smc_clc_msg_smcd *pclc_smcd;
struct smc_clc_msg_trail *trl;
int len, i, plen, rc; int len, i, plen, rc;
int reason_code = 0; int reason_code = 0;
struct kvec vec[5]; struct kvec vec[5];
struct msghdr msg; struct msghdr msg;
pclc = kzalloc(sizeof(*pclc), GFP_KERNEL);
if (!pclc)
return -ENOMEM;
pclc_base = &pclc->pclc_base;
pclc_smcd = &pclc->pclc_smcd;
pclc_prfx = &pclc->pclc_prfx;
ipv6_prfx = pclc->pclc_prfx_ipv6;
trl = &pclc->pclc_trl;
/* retrieve ip prefixes for CLC proposal msg */ /* retrieve ip prefixes for CLC proposal msg */
rc = smc_clc_prfx_set(smc->clcsock, &pclc_prfx, ipv6_prfx); rc = smc_clc_prfx_set(smc->clcsock, pclc_prfx, ipv6_prfx);
if (rc) if (rc) {
kfree(pclc);
return SMC_CLC_DECL_CNFERR; /* configuration error */ return SMC_CLC_DECL_CNFERR; /* configuration error */
}
/* send SMC Proposal CLC message */ /* send SMC Proposal CLC message */
plen = sizeof(pclc) + sizeof(pclc_prfx) + plen = sizeof(*pclc_base) + sizeof(*pclc_prfx) +
(pclc_prfx.ipv6_prefixes_cnt * sizeof(ipv6_prfx[0])) + (pclc_prfx->ipv6_prefixes_cnt * sizeof(ipv6_prfx[0])) +
sizeof(trl); sizeof(*trl);
memset(&pclc, 0, sizeof(pclc)); memcpy(pclc_base->hdr.eyecatcher, SMC_EYECATCHER,
memcpy(pclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); sizeof(SMC_EYECATCHER));
pclc.hdr.type = SMC_CLC_PROPOSAL; pclc_base->hdr.type = SMC_CLC_PROPOSAL;
pclc.hdr.version = SMC_V1; /* SMC version */ pclc_base->hdr.version = SMC_V1; /* SMC version */
pclc.hdr.path = smc_type; pclc_base->hdr.path = smc_type;
if (smc_type == SMC_TYPE_R || smc_type == SMC_TYPE_B) { if (smc_type == SMC_TYPE_R || smc_type == SMC_TYPE_B) {
/* add SMC-R specifics */ /* add SMC-R specifics */
memcpy(pclc.lcl.id_for_peer, local_systemid, memcpy(pclc_base->lcl.id_for_peer, local_systemid,
sizeof(local_systemid)); sizeof(local_systemid));
memcpy(&pclc.lcl.gid, ini->ib_gid, SMC_GID_SIZE); memcpy(pclc_base->lcl.gid, ini->ib_gid, SMC_GID_SIZE);
memcpy(&pclc.lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1], memcpy(pclc_base->lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1],
ETH_ALEN); ETH_ALEN);
pclc.iparea_offset = htons(0); pclc_base->iparea_offset = htons(0);
} }
if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) { if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) {
/* add SMC-D specifics */ /* add SMC-D specifics */
memset(&pclc_smcd, 0, sizeof(pclc_smcd)); plen += sizeof(*pclc_smcd);
plen += sizeof(pclc_smcd); pclc_base->iparea_offset = htons(sizeof(*pclc_smcd));
pclc.iparea_offset = htons(SMC_CLC_PROPOSAL_MAX_OFFSET); pclc_smcd->gid = ini->ism_dev->local_gid;
pclc_smcd.gid = ini->ism_dev->local_gid;
} }
pclc.hdr.length = htons(plen); pclc_base->hdr.length = htons(plen);
memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
i = 0; i = 0;
vec[i].iov_base = &pclc; vec[i].iov_base = pclc_base;
vec[i++].iov_len = sizeof(pclc); vec[i++].iov_len = sizeof(*pclc_base);
if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) { if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) {
vec[i].iov_base = &pclc_smcd; vec[i].iov_base = pclc_smcd;
vec[i++].iov_len = sizeof(pclc_smcd); vec[i++].iov_len = sizeof(*pclc_smcd);
} }
vec[i].iov_base = &pclc_prfx; vec[i].iov_base = pclc_prfx;
vec[i++].iov_len = sizeof(pclc_prfx); vec[i++].iov_len = sizeof(*pclc_prfx);
if (pclc_prfx.ipv6_prefixes_cnt > 0) { if (pclc_prfx->ipv6_prefixes_cnt > 0) {
vec[i].iov_base = &ipv6_prfx[0]; vec[i].iov_base = ipv6_prfx;
vec[i++].iov_len = pclc_prfx.ipv6_prefixes_cnt * vec[i++].iov_len = pclc_prfx->ipv6_prefixes_cnt *
sizeof(ipv6_prfx[0]); sizeof(ipv6_prfx[0]);
} }
vec[i].iov_base = &trl; vec[i].iov_base = trl;
vec[i++].iov_len = sizeof(trl); vec[i++].iov_len = sizeof(*trl);
/* due to the few bytes needed for clc-handshake this cannot block */ /* due to the few bytes needed for clc-handshake this cannot block */
len = kernel_sendmsg(smc->clcsock, &msg, vec, i, plen); len = kernel_sendmsg(smc->clcsock, &msg, vec, i, plen);
if (len < 0) { if (len < 0) {
smc->sk.sk_err = smc->clcsock->sk->sk_err; smc->sk.sk_err = smc->clcsock->sk->sk_err;
reason_code = -smc->sk.sk_err; reason_code = -smc->sk.sk_err;
} else if (len < (int)sizeof(pclc)) { } else if (len < ntohs(pclc_base->hdr.length)) {
reason_code = -ENETUNREACH; reason_code = -ENETUNREACH;
smc->sk.sk_err = -reason_code; smc->sk.sk_err = -reason_code;
} }
kfree(pclc);
return reason_code; return reason_code;
} }
......
...@@ -110,14 +110,13 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */ ...@@ -110,14 +110,13 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */
__be16 iparea_offset; /* offset to IP address information area */ __be16 iparea_offset; /* offset to IP address information area */
} __aligned(4); } __aligned(4);
#define SMC_CLC_PROPOSAL_MAX_OFFSET 0x28 struct smc_clc_msg_proposal_area {
#define SMC_CLC_PROPOSAL_MAX_PREFIX (SMC_CLC_MAX_V6_PREFIX * \ struct smc_clc_msg_proposal pclc_base;
sizeof(struct smc_clc_ipv6_prefix)) struct smc_clc_msg_smcd pclc_smcd;
#define SMC_CLC_MAX_LEN (sizeof(struct smc_clc_msg_proposal) + \ struct smc_clc_msg_proposal_prefix pclc_prfx;
SMC_CLC_PROPOSAL_MAX_OFFSET + \ struct smc_clc_ipv6_prefix pclc_prfx_ipv6[SMC_CLC_MAX_V6_PREFIX];
sizeof(struct smc_clc_msg_proposal_prefix) + \ struct smc_clc_msg_trail pclc_trl;
SMC_CLC_PROPOSAL_MAX_PREFIX + \ };
sizeof(struct smc_clc_msg_trail))
struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */ struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */
struct smc_clc_msg_hdr hdr; struct smc_clc_msg_hdr hdr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment