Skip to content

Commit

Permalink
net/smc: fix sender_free computation
Browse files Browse the repository at this point in the history
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: e82f2e3 ("net/smc: optimize consumer cursor updates")
Signed-off-by: Ursula Braun <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Ursula Braun authored and davem330 committed Feb 4, 2019
1 parent ad6f317 commit b8649ef
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 4 deletions.
5 changes: 3 additions & 2 deletions net/smc/smc_cdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down
26 changes: 25 additions & 1 deletion net/smc/smc_cdc.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ static inline void smcd_curs_copy(union smcd_cdc_cursor *tgt,
#endif
}

/* calculate cursor difference between old and new, where old <= new */
/* calculate cursor difference between old and new, where old <= new and
* difference cannot exceed size
*/
static inline int smc_curs_diff(unsigned int size,
union smc_host_cursor *old,
union smc_host_cursor *new)
Expand All @@ -185,6 +187,28 @@ static inline int smc_curs_comp(unsigned int size,
return smc_curs_diff(size, old, new);
}

/* calculate cursor difference between old and new, where old <= new and
* difference may exceed size
*/
static inline int smc_curs_diff_large(unsigned int size,
union smc_host_cursor *old,
union smc_host_cursor *new)
{
if (old->wrap < new->wrap)
return min_t(int,
(size - old->count) + new->count +
(new->wrap - old->wrap - 1) * size,
size);

if (old->wrap > new->wrap) /* wrap has switched from 0xffff to 0x0000 */
return min_t(int,
(size - old->count) + new->count +
(new->wrap + 0xffff - old->wrap) * size,
size);

return max_t(int, 0, (new->count - old->count));
}

static inline void smc_host_cursor_to_cdc(union smc_cdc_cursor *peer,
union smc_host_cursor *local,
struct smc_connection *conn)
Expand Down
3 changes: 2 additions & 1 deletion net/smc/smc_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,8 @@ void smc_tx_consumer_update(struct smc_connection *conn, bool force)
if (to_confirm > conn->rmbe_update_limit) {
smc_curs_copy(&prod, &conn->local_rx_ctrl.prod, conn);
sender_free = conn->rmb_desc->len -
smc_curs_diff(conn->rmb_desc->len, &prod, &cfed);
smc_curs_diff_large(conn->rmb_desc->len,
&cfed, &prod);
}

if (conn->local_rx_ctrl.prod_flags.cons_curs_upd_req ||
Expand Down

0 comments on commit b8649ef

Please sign in to comment.