OSDN Git Service

net/smc: pre-fetch send buffer outside of send_lock
authorKarsten Graul <kgraul@linux.ibm.com>
Sat, 30 May 2020 14:42:37 +0000 (16:42 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 31 May 2020 01:12:25 +0000 (18:12 -0700)
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: Karsten Graul <kgraul@linux.ibm.com>
Reviewed-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/smc_cdc.c
net/smc/smc_cdc.h
net/smc/smc_core.c

index b2b85e1..a47e885 100644 (file)
@@ -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 */
-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_link *link = conn->lnk;
-       struct smc_cdc_tx_pend *pend;
-       struct smc_wr_buf *wr_buf;
        struct smc_cdc_msg *peer;
        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->common.type = local->common.type;
        peer->len = local->len;
index 2ddcc5f..0a0a89a 100644 (file)
@@ -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);
 int smc_cdc_get_slot_and_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;
 void smcd_cdc_rx_init(struct smc_connection *conn);
 
index 65de700..7964a21 100644 (file)
@@ -483,7 +483,8 @@ static int smc_write_space(struct smc_connection *conn)
        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;
        union smc_host_cursor cons, fin;
@@ -520,11 +521,14 @@ static int smc_switch_cursor(struct smc_sock *smc)
 
        if (smc->sk.sk_state != SMC_INIT &&
            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) {
                        schedule_delayed_work(&conn->tx_work, 0);
                        smc->sk.sk_data_ready(&smc->sk);
                }
+       } else {
+               smc_wr_tx_put_slot(conn->lnk,
+                                  (struct smc_wr_tx_pend_priv *)pend);
        }
        return rc;
 }
@@ -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 *to_lnk = NULL;
+       struct smc_cdc_tx_pend *pend;
        struct smc_connection *conn;
+       struct smc_wr_buf *wr_buf;
        struct smc_sock *smc;
        struct rb_node *node;
        int i, rc = 0;
@@ -582,10 +588,16 @@ again:
                }
                sock_hold(&smc->sk);
                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() */
                spin_lock_bh(&conn->send_lock);
                conn->lnk = to_lnk;
-               rc = smc_switch_cursor(smc);
+               rc = smc_switch_cursor(smc, pend, wr_buf);
                spin_unlock_bh(&conn->send_lock);
                sock_put(&smc->sk);
                if (rc) {