summaryrefslogtreecommitdiff
path: root/net/smc
diff options
context:
space:
mode:
Diffstat (limited to 'net/smc')
-rw-r--r--net/smc/af_smc.c2
-rw-r--r--net/smc/smc_inet.c16
-rw-r--r--net/smc/smc_llc.c3
3 files changed, 20 insertions, 1 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index cff910cedbfc..e9f93b3ab435 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -409,13 +409,13 @@ void smc_sk_init(struct net *net, struct sock *sk, int protocol)
"sk_lock-AF_SMC", &smc_key);
spin_lock_init(&smc->accept_q_lock);
spin_lock_init(&smc->conn.send_lock);
- sk->sk_prot->hash(sk);
mutex_init(&smc->clcsock_release_lock);
smc_init_saved_callbacks(smc);
smc->limit_smc_hs = net->smc.limit_smc_hs;
smc->use_fallback = false; /* assume rdma capability first */
smc->fallback_rsn = 0;
smc_close_init(smc);
+ sk->sk_prot->hash(sk);
}
static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
diff --git a/net/smc/smc_inet.c b/net/smc/smc_inet.c
index a94084b4a498..520b666fdd8f 100644
--- a/net/smc/smc_inet.c
+++ b/net/smc/smc_inet.c
@@ -15,13 +15,16 @@
#include "smc_inet.h"
#include "smc.h"
+#include "smc_close.h"
static int smc_inet_init_sock(struct sock *sk);
+static void smc_inet_destroy_sock(struct sock *sk);
static struct proto smc_inet_prot = {
.name = "INET_SMC",
.owner = THIS_MODULE,
.init = smc_inet_init_sock,
+ .destroy = smc_inet_destroy_sock,
.hash = smc_hash_sk,
.unhash = smc_unhash_sk,
.release_cb = smc_release_cb,
@@ -68,6 +71,7 @@ static struct proto smc_inet6_prot = {
.name = "INET6_SMC",
.owner = THIS_MODULE,
.init = smc_inet_init_sock,
+ .destroy = smc_inet_destroy_sock,
.hash = smc_hash_sk,
.unhash = smc_unhash_sk,
.release_cb = smc_release_cb,
@@ -116,6 +120,18 @@ static int smc_inet_init_sock(struct sock *sk)
return smc_create_clcsk(net, sk, sk->sk_family);
}
+static void smc_inet_destroy_sock(struct sock *sk)
+{
+ /* The sock is hashed and smc_diag dumps dereference smc->clcsock
+ * without clcsock_release_lock, while sk_common_release() calls
+ * .destroy before .unhash. Unhash first, as __smc_release() does,
+ * so no dump can observe the clcsock being released; the second
+ * unhash is a no-op.
+ */
+ sk->sk_prot->unhash(sk);
+ smc_clcsock_release(smc_sk(sk));
+}
+
int __init smc_inet_init(void)
{
int rc;
diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
index 481b0495b0d3..c9ccd8480369 100644
--- a/net/smc/smc_llc.c
+++ b/net/smc/smc_llc.c
@@ -341,6 +341,7 @@ again:
void smc_llc_flow_stop(struct smc_link_group *lgr, struct smc_llc_flow *flow)
{
spin_lock_bh(&lgr->llc_flow_lock);
+ smc_llc_flow_qentry_del(flow);
memset(flow, 0, sizeof(*flow));
flow->type = SMC_LLC_FLOW_NONE;
spin_unlock_bh(&lgr->llc_flow_lock);
@@ -1945,6 +1946,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
if (lgr->llc_flow_lcl.type ==
SMC_LLC_FLOW_REQ_ADD_LINK) {
/* server started add_link processing */
+ /* free any qentry stashed in REQ_ADD_LINK state */
+ smc_llc_flow_qentry_del(&lgr->llc_flow_lcl);
lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK;
smc_llc_flow_qentry_set(&lgr->llc_flow_lcl,
qentry);