Commit b8ded9de authored by Karsten Graul's avatar Karsten Graul Committed by David S. Miller

net/smc: pre-fetch send buffer outside of send_lock

Pre-fetch send buffer for the CDC validation message before entering the
send_lock. Without that the send call might fail with -EBUSY because
there are no free buffers and waiting for buffers is not possible under
send_lock.
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Reviewed-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b86a3722
...@@ -116,19 +116,15 @@ int smc_cdc_msg_send(struct smc_connection *conn, ...@@ -116,19 +116,15 @@ int smc_cdc_msg_send(struct smc_connection *conn,
} }
/* send a validation msg indicating the move of a conn to an other QP link */ /* send a validation msg indicating the move of a conn to an other QP link */
int smcr_cdc_msg_send_validation(struct smc_connection *conn) int smcr_cdc_msg_send_validation(struct smc_connection *conn,
struct smc_cdc_tx_pend *pend,
struct smc_wr_buf *wr_buf)
{ {
struct smc_host_cdc_msg *local = &conn->local_tx_ctrl; struct smc_host_cdc_msg *local = &conn->local_tx_ctrl;
struct smc_link *link = conn->lnk; struct smc_link *link = conn->lnk;
struct smc_cdc_tx_pend *pend;
struct smc_wr_buf *wr_buf;
struct smc_cdc_msg *peer; struct smc_cdc_msg *peer;
int rc; int rc;
rc = smc_cdc_get_free_slot(conn, link, &wr_buf, NULL, &pend);
if (rc)
return rc;
peer = (struct smc_cdc_msg *)wr_buf; peer = (struct smc_cdc_msg *)wr_buf;
peer->common.type = local->common.type; peer->common.type = local->common.type;
peer->len = local->len; peer->len = local->len;
......
...@@ -296,7 +296,9 @@ int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf, ...@@ -296,7 +296,9 @@ int smc_cdc_msg_send(struct smc_connection *conn, struct smc_wr_buf *wr_buf,
struct smc_cdc_tx_pend *pend); struct smc_cdc_tx_pend *pend);
int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn); int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn);
int smcd_cdc_msg_send(struct smc_connection *conn); int smcd_cdc_msg_send(struct smc_connection *conn);
int smcr_cdc_msg_send_validation(struct smc_connection *conn); int smcr_cdc_msg_send_validation(struct smc_connection *conn,
struct smc_cdc_tx_pend *pend,
struct smc_wr_buf *wr_buf);
int smc_cdc_init(void) __init; int smc_cdc_init(void) __init;
void smcd_cdc_rx_init(struct smc_connection *conn); void smcd_cdc_rx_init(struct smc_connection *conn);
......
...@@ -483,7 +483,8 @@ static int smc_write_space(struct smc_connection *conn) ...@@ -483,7 +483,8 @@ static int smc_write_space(struct smc_connection *conn)
return space; return space;
} }
static int smc_switch_cursor(struct smc_sock *smc) static int smc_switch_cursor(struct smc_sock *smc, struct smc_cdc_tx_pend *pend,
struct smc_wr_buf *wr_buf)
{ {
struct smc_connection *conn = &smc->conn; struct smc_connection *conn = &smc->conn;
union smc_host_cursor cons, fin; union smc_host_cursor cons, fin;
...@@ -520,11 +521,14 @@ static int smc_switch_cursor(struct smc_sock *smc) ...@@ -520,11 +521,14 @@ static int smc_switch_cursor(struct smc_sock *smc)
if (smc->sk.sk_state != SMC_INIT && if (smc->sk.sk_state != SMC_INIT &&
smc->sk.sk_state != SMC_CLOSED) { smc->sk.sk_state != SMC_CLOSED) {
rc = smcr_cdc_msg_send_validation(conn); rc = smcr_cdc_msg_send_validation(conn, pend, wr_buf);
if (!rc) { if (!rc) {
schedule_delayed_work(&conn->tx_work, 0); schedule_delayed_work(&conn->tx_work, 0);
smc->sk.sk_data_ready(&smc->sk); smc->sk.sk_data_ready(&smc->sk);
} }
} else {
smc_wr_tx_put_slot(conn->lnk,
(struct smc_wr_tx_pend_priv *)pend);
} }
return rc; return rc;
} }
...@@ -533,7 +537,9 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr, ...@@ -533,7 +537,9 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr,
struct smc_link *from_lnk, bool is_dev_err) struct smc_link *from_lnk, bool is_dev_err)
{ {
struct smc_link *to_lnk = NULL; struct smc_link *to_lnk = NULL;
struct smc_cdc_tx_pend *pend;
struct smc_connection *conn; struct smc_connection *conn;
struct smc_wr_buf *wr_buf;
struct smc_sock *smc; struct smc_sock *smc;
struct rb_node *node; struct rb_node *node;
int i, rc = 0; int i, rc = 0;
...@@ -582,10 +588,16 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr, ...@@ -582,10 +588,16 @@ struct smc_link *smc_switch_conns(struct smc_link_group *lgr,
} }
sock_hold(&smc->sk); sock_hold(&smc->sk);
read_unlock_bh(&lgr->conns_lock); read_unlock_bh(&lgr->conns_lock);
/* pre-fetch buffer outside of send_lock, might sleep */
rc = smc_cdc_get_free_slot(conn, to_lnk, &wr_buf, NULL, &pend);
if (rc) {
smcr_link_down_cond_sched(to_lnk);
return NULL;
}
/* avoid race with smcr_tx_sndbuf_nonempty() */ /* avoid race with smcr_tx_sndbuf_nonempty() */
spin_lock_bh(&conn->send_lock); spin_lock_bh(&conn->send_lock);
conn->lnk = to_lnk; conn->lnk = to_lnk;
rc = smc_switch_cursor(smc); rc = smc_switch_cursor(smc, pend, wr_buf);
spin_unlock_bh(&conn->send_lock); spin_unlock_bh(&conn->send_lock);
sock_put(&smc->sk); sock_put(&smc->sk);
if (rc) { if (rc) {
......
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