diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/smc/af_smc.c | 9 | ||||
-rw-r--r-- | net/smc/smc_core.c | 26 | ||||
-rw-r--r-- | net/smc/smc_core.h | 2 | ||||
-rw-r--r-- | net/smc/smc_llc.c | 9 |
4 files changed, 34 insertions, 12 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 20d6d3fbb86c..6663a63be9e4 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -344,6 +344,13 @@ static int smcr_lgr_reg_rmbs(struct smc_link *link, struct smc_link_group *lgr = link->lgr; int i, rc = 0; + rc = smc_llc_flow_initiate(lgr, SMC_LLC_FLOW_RKEY); + if (rc) + return rc; + /* protect against parallel smc_llc_cli_rkey_exchange() and + * parallel smcr_link_reg_rmb() + */ + mutex_lock(&lgr->llc_conf_mutex); for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { if (lgr->lnk[i].state != SMC_LNK_ACTIVE) continue; @@ -360,6 +367,8 @@ static int smcr_lgr_reg_rmbs(struct smc_link *link, } rmb_desc->is_conf_rkey = true; out: + mutex_unlock(&lgr->llc_conf_mutex); + smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); return rc; } diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index c905675017c7..4c3af05d76a5 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -448,11 +448,21 @@ out: static void smcr_buf_unuse(struct smc_buf_desc *rmb_desc, struct smc_link_group *lgr) { + int rc; + if (rmb_desc->is_conf_rkey && !list_empty(&lgr->list)) { /* unregister rmb with peer */ - smc_llc_do_delete_rkey(lgr, rmb_desc); - rmb_desc->is_conf_rkey = false; + rc = smc_llc_flow_initiate(lgr, SMC_LLC_FLOW_RKEY); + if (!rc) { + /* protect against smc_llc_cli_rkey_exchange() */ + mutex_lock(&lgr->llc_conf_mutex); + smc_llc_do_delete_rkey(lgr, rmb_desc); + rmb_desc->is_conf_rkey = false; + mutex_unlock(&lgr->llc_conf_mutex); + smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); + } } + if (rmb_desc->is_reg_err) { /* buf registration failed, reuse not possible */ mutex_lock(&lgr->rmbs_lock); @@ -552,6 +562,7 @@ static void smcr_rtoken_clear_link(struct smc_link *lnk) } } +/* must be called under lgr->llc_conf_mutex lock */ void smcr_link_clear(struct smc_link *lnk) { struct smc_ib_device *smcibdev; @@ -1170,7 +1181,9 @@ free_table: return rc; } -/* register a new rmb on IB device */ +/* register a new rmb on IB device, + * must be called under lgr->llc_conf_mutex lock + */ int smcr_link_reg_rmb(struct smc_link *link, struct smc_buf_desc *rmb_desc) { if (list_empty(&link->lgr->list)) @@ -1224,7 +1237,9 @@ int smcr_buf_map_lgr(struct smc_link *lnk) return 0; } -/* register all used buffers of lgr for a new link */ +/* register all used buffers of lgr for a new link, + * must be called under lgr->llc_conf_mutex lock + */ int smcr_buf_reg_lgr(struct smc_link *lnk) { struct smc_link_group *lgr = lnk->lgr; @@ -1278,6 +1293,8 @@ static int smcr_buf_map_usable_links(struct smc_link_group *lgr, { int i, rc = 0; + /* protect against parallel link reconfiguration */ + mutex_lock(&lgr->llc_conf_mutex); for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { struct smc_link *lnk = &lgr->lnk[i]; @@ -1289,6 +1306,7 @@ static int smcr_buf_map_usable_links(struct smc_link_group *lgr, } } out: + mutex_unlock(&lgr->llc_conf_mutex); return rc; } diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index 61ddb5264936..aa198dd0f0e4 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -248,6 +248,8 @@ struct smc_link_group { /* queue for llc events */ spinlock_t llc_event_q_lock; /* protects llc_event_q */ + struct mutex llc_conf_mutex; + /* protects lgr reconfig. */ struct work_struct llc_event_work; /* llc event worker */ wait_queue_head_t llc_waiter; diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index 171835926db6..ceed3c89926f 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c @@ -848,6 +848,7 @@ void smc_llc_lgr_init(struct smc_link_group *lgr, struct smc_sock *smc) spin_lock_init(&lgr->llc_event_q_lock); spin_lock_init(&lgr->llc_flow_lock); init_waitqueue_head(&lgr->llc_waiter); + mutex_init(&lgr->llc_conf_mutex); lgr->llc_testlink_time = net->ipv4.sysctl_tcp_keepalive_time; } @@ -897,9 +898,6 @@ int smc_llc_do_confirm_rkey(struct smc_link *send_link, struct smc_llc_qentry *qentry = NULL; int rc = 0; - rc = smc_llc_flow_initiate(lgr, SMC_LLC_FLOW_RKEY); - if (rc) - return rc; rc = smc_llc_send_confirm_rkey(send_link, rmb_desc); if (rc) goto out; @@ -911,7 +909,6 @@ int smc_llc_do_confirm_rkey(struct smc_link *send_link, out: if (qentry) smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); - smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); return rc; } @@ -927,9 +924,6 @@ int smc_llc_do_delete_rkey(struct smc_link_group *lgr, if (!send_link) return -ENOLINK; - rc = smc_llc_flow_initiate(lgr, SMC_LLC_FLOW_RKEY); - if (rc) - return rc; /* protected by llc_flow control */ rc = smc_llc_send_delete_rkey(send_link, rmb_desc); if (rc) @@ -942,7 +936,6 @@ int smc_llc_do_delete_rkey(struct smc_link_group *lgr, out: if (qentry) smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); - smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); return rc; } |