Merge branch 'smc-fixes'

Karsten Graul says:

====================
net/smc: fixes 2020-09-03

Please apply the following patch series for smc to netdev's net tree.

Patch 1 fixes the toleration of older SMC implementations. Patch 2
takes care of a problem that happens when SMCR is used after SMCD
initialization failed. Patch 3 fixes a problem with freed send buffers,
and patch 4 corrects refcounting when SMC terminates due to device
removal.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-09-03 16:52:33 -07:00
commit b61ac5bb42
3 changed files with 25 additions and 8 deletions

View File

@ -116,7 +116,6 @@ static void smc_close_cancel_work(struct smc_sock *smc)
cancel_work_sync(&smc->conn.close_work); cancel_work_sync(&smc->conn.close_work);
cancel_delayed_work_sync(&smc->conn.tx_work); cancel_delayed_work_sync(&smc->conn.tx_work);
lock_sock(sk); lock_sock(sk);
sk->sk_state = SMC_CLOSED;
} }
/* terminate smc socket abnormally - active abort /* terminate smc socket abnormally - active abort
@ -134,22 +133,22 @@ void smc_close_active_abort(struct smc_sock *smc)
} }
switch (sk->sk_state) { switch (sk->sk_state) {
case SMC_ACTIVE: case SMC_ACTIVE:
sk->sk_state = SMC_PEERABORTWAIT;
smc_close_cancel_work(smc);
sk->sk_state = SMC_CLOSED;
sock_put(sk); /* passive closing */
break;
case SMC_APPCLOSEWAIT1: case SMC_APPCLOSEWAIT1:
case SMC_APPCLOSEWAIT2: case SMC_APPCLOSEWAIT2:
sk->sk_state = SMC_PEERABORTWAIT;
smc_close_cancel_work(smc); smc_close_cancel_work(smc);
if (sk->sk_state != SMC_PEERABORTWAIT)
break;
sk->sk_state = SMC_CLOSED; sk->sk_state = SMC_CLOSED;
sock_put(sk); /* postponed passive closing */ sock_put(sk); /* (postponed) passive closing */
break; break;
case SMC_PEERCLOSEWAIT1: case SMC_PEERCLOSEWAIT1:
case SMC_PEERCLOSEWAIT2: case SMC_PEERCLOSEWAIT2:
case SMC_PEERFINCLOSEWAIT: case SMC_PEERFINCLOSEWAIT:
sk->sk_state = SMC_PEERABORTWAIT; sk->sk_state = SMC_PEERABORTWAIT;
smc_close_cancel_work(smc); smc_close_cancel_work(smc);
if (sk->sk_state != SMC_PEERABORTWAIT)
break;
sk->sk_state = SMC_CLOSED; sk->sk_state = SMC_CLOSED;
smc_conn_free(&smc->conn); smc_conn_free(&smc->conn);
release_clcsock = true; release_clcsock = true;
@ -159,6 +158,8 @@ void smc_close_active_abort(struct smc_sock *smc)
case SMC_APPFINCLOSEWAIT: case SMC_APPFINCLOSEWAIT:
sk->sk_state = SMC_PEERABORTWAIT; sk->sk_state = SMC_PEERABORTWAIT;
smc_close_cancel_work(smc); smc_close_cancel_work(smc);
if (sk->sk_state != SMC_PEERABORTWAIT)
break;
sk->sk_state = SMC_CLOSED; sk->sk_state = SMC_CLOSED;
smc_conn_free(&smc->conn); smc_conn_free(&smc->conn);
release_clcsock = true; release_clcsock = true;

View File

@ -1356,6 +1356,8 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
if (ini->is_smcd) { if (ini->is_smcd) {
conn->rx_off = sizeof(struct smcd_cdc_msg); conn->rx_off = sizeof(struct smcd_cdc_msg);
smcd_cdc_rx_init(conn); /* init tasklet for this conn */ smcd_cdc_rx_init(conn); /* init tasklet for this conn */
} else {
conn->rx_off = 0;
} }
#ifndef KERNEL_HAS_ATOMIC64 #ifndef KERNEL_HAS_ATOMIC64
spin_lock_init(&conn->acurs_lock); spin_lock_init(&conn->acurs_lock);
@ -1777,6 +1779,7 @@ int smc_buf_create(struct smc_sock *smc, bool is_smcd)
list_del(&smc->conn.sndbuf_desc->list); list_del(&smc->conn.sndbuf_desc->list);
mutex_unlock(&smc->conn.lgr->sndbufs_lock); mutex_unlock(&smc->conn.lgr->sndbufs_lock);
smc_buf_free(smc->conn.lgr, false, smc->conn.sndbuf_desc); smc_buf_free(smc->conn.lgr, false, smc->conn.sndbuf_desc);
smc->conn.sndbuf_desc = NULL;
} }
return rc; return rc;
} }

View File

@ -841,6 +841,9 @@ int smc_llc_cli_add_link(struct smc_link *link, struct smc_llc_qentry *qentry)
struct smc_init_info ini; struct smc_init_info ini;
int lnk_idx, rc = 0; int lnk_idx, rc = 0;
if (!llc->qp_mtu)
goto out_reject;
ini.vlan_id = lgr->vlan_id; ini.vlan_id = lgr->vlan_id;
smc_pnet_find_alt_roce(lgr, &ini, link->smcibdev); smc_pnet_find_alt_roce(lgr, &ini, link->smcibdev);
if (!memcmp(llc->sender_gid, link->peer_gid, SMC_GID_SIZE) && if (!memcmp(llc->sender_gid, link->peer_gid, SMC_GID_SIZE) &&
@ -917,10 +920,20 @@ static void smc_llc_cli_add_link_invite(struct smc_link *link,
kfree(qentry); kfree(qentry);
} }
static bool smc_llc_is_empty_llc_message(union smc_llc_msg *llc)
{
int i;
for (i = 0; i < ARRAY_SIZE(llc->raw.data); i++)
if (llc->raw.data[i])
return false;
return true;
}
static bool smc_llc_is_local_add_link(union smc_llc_msg *llc) static bool smc_llc_is_local_add_link(union smc_llc_msg *llc)
{ {
if (llc->raw.hdr.common.type == SMC_LLC_ADD_LINK && if (llc->raw.hdr.common.type == SMC_LLC_ADD_LINK &&
!llc->add_link.qp_mtu && !llc->add_link.link_num) smc_llc_is_empty_llc_message(llc))
return true; return true;
return false; return false;
} }