summaryrefslogtreecommitdiffstats
path: root/net/smc/smc_cdc.c
diff options
context:
space:
mode:
authorUrsula Braun <ubraun@linux.ibm.com>2019-02-04 13:44:45 +0100
committerDavid S. Miller <davem@davemloft.net>2019-02-04 09:11:19 -0800
commitb8649efad879c69c7ab1f19ce8814fcabef1f72b (patch)
treec5f16db7dbde8bb5da8db0b74f538a2a58c78036 /net/smc/smc_cdc.c
parentad6f317f720f4a3121756c23831a43dda9b095e5 (diff)
downloadlinux-b8649efad879c69c7ab1f19ce8814fcabef1f72b.tar.bz2
net/smc: fix sender_free computation
In some scenarios a separate consumer cursor update is necessary. The decision is made in smc_tx_consumer_cursor_update(). The sender_free computation could be wrong: The rx confirmed cursor is always smaller than or equal to the rx producer cursor. The parameters in the smc_curs_diff() call have to be exchanged, otherwise sender_free might even be negative. And if more data arrives local_rx_ctrl.prod might be updated, enabling a cursor difference between local_rx_ctrl.prod and rx confirmed cursor larger than the RMB size. This case is not covered by smc_curs_diff(). Thus function smc_curs_diff_large() is introduced here. If a recvmsg() is processed in parallel, local_tx_ctrl.cons might change during smc_cdc_msg_send. Make sure rx_curs_confirmed is updated with the actually sent local_tx_ctrl.cons value. Fixes: e82f2e31f559 ("net/smc: optimize consumer cursor updates") Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/smc/smc_cdc.c')
-rw-r--r--net/smc/smc_cdc.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/net/smc/smc_cdc.c b/net/smc/smc_cdc.c
index b80ef104ab4e..a712c9f8699b 100644
--- a/net/smc/smc_cdc.c
+++ b/net/smc/smc_cdc.c
@@ -91,6 +91,7 @@ int smc_cdc_msg_send(struct smc_connection *conn,
struct smc_wr_buf *wr_buf,
struct smc_cdc_tx_pend *pend)
{
+ union smc_host_cursor cfed;
struct smc_link *link;
int rc;
@@ -102,10 +103,10 @@ int smc_cdc_msg_send(struct smc_connection *conn,
conn->local_tx_ctrl.seqno = conn->tx_cdc_seq;
smc_host_msg_to_cdc((struct smc_cdc_msg *)wr_buf,
&conn->local_tx_ctrl, conn);
+ smc_curs_copy(&cfed, &((struct smc_host_cdc_msg *)wr_buf)->cons, conn);
rc = smc_wr_tx_send(link, (struct smc_wr_tx_pend_priv *)pend);
if (!rc)
- smc_curs_copy(&conn->rx_curs_confirmed,
- &conn->local_tx_ctrl.cons, conn);
+ smc_curs_copy(&conn->rx_curs_confirmed, &cfed, conn);
return rc;
}