Commit b9a22dd9 authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller

net/smc: atomic SMCD cursor handling

Running uperf tests with SMCD on LPARs results in corrupted cursors.
SMCD cursors should be treated atomically to fix cursor corruption.
Signed-off-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0512f69e
...@@ -81,7 +81,7 @@ static inline void smc_cdc_add_pending_send(struct smc_connection *conn, ...@@ -81,7 +81,7 @@ static inline void smc_cdc_add_pending_send(struct smc_connection *conn,
sizeof(struct smc_cdc_msg) > SMC_WR_BUF_SIZE, sizeof(struct smc_cdc_msg) > SMC_WR_BUF_SIZE,
"must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_cdc_msg)"); "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_cdc_msg)");
BUILD_BUG_ON_MSG( BUILD_BUG_ON_MSG(
sizeof(struct smc_cdc_msg) != SMC_WR_TX_SIZE, offsetofend(struct smc_cdc_msg, reserved) > SMC_WR_TX_SIZE,
"must adapt SMC_WR_TX_SIZE to sizeof(struct smc_cdc_msg); if not all smc_wr upper layer protocols use the same message size any more, must start to set link->wr_tx_sges[i].length on each individual smc_wr_tx_send()"); "must adapt SMC_WR_TX_SIZE to sizeof(struct smc_cdc_msg); if not all smc_wr upper layer protocols use the same message size any more, must start to set link->wr_tx_sges[i].length on each individual smc_wr_tx_send()");
BUILD_BUG_ON_MSG( BUILD_BUG_ON_MSG(
sizeof(struct smc_cdc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE, sizeof(struct smc_cdc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE,
...@@ -177,23 +177,24 @@ void smc_cdc_tx_dismiss_slots(struct smc_connection *conn) ...@@ -177,23 +177,24 @@ void smc_cdc_tx_dismiss_slots(struct smc_connection *conn)
int smcd_cdc_msg_send(struct smc_connection *conn) int smcd_cdc_msg_send(struct smc_connection *conn)
{ {
struct smc_sock *smc = container_of(conn, struct smc_sock, conn); struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
union smc_host_cursor curs;
struct smcd_cdc_msg cdc; struct smcd_cdc_msg cdc;
int rc, diff; int rc, diff;
memset(&cdc, 0, sizeof(cdc)); memset(&cdc, 0, sizeof(cdc));
cdc.common.type = SMC_CDC_MSG_TYPE; cdc.common.type = SMC_CDC_MSG_TYPE;
cdc.prod_wrap = conn->local_tx_ctrl.prod.wrap; curs.acurs.counter = atomic64_read(&conn->local_tx_ctrl.prod.acurs);
cdc.prod_count = conn->local_tx_ctrl.prod.count; cdc.prod.wrap = curs.wrap;
cdc.prod.count = curs.count;
cdc.cons_wrap = conn->local_tx_ctrl.cons.wrap; curs.acurs.counter = atomic64_read(&conn->local_tx_ctrl.cons.acurs);
cdc.cons_count = conn->local_tx_ctrl.cons.count; cdc.cons.wrap = curs.wrap;
cdc.prod_flags = conn->local_tx_ctrl.prod_flags; cdc.cons.count = curs.count;
cdc.conn_state_flags = conn->local_tx_ctrl.conn_state_flags; cdc.cons.prod_flags = conn->local_tx_ctrl.prod_flags;
cdc.cons.conn_state_flags = conn->local_tx_ctrl.conn_state_flags;
rc = smcd_tx_ism_write(conn, &cdc, sizeof(cdc), 0, 1); rc = smcd_tx_ism_write(conn, &cdc, sizeof(cdc), 0, 1);
if (rc) if (rc)
return rc; return rc;
smc_curs_copy(&conn->rx_curs_confirmed, &conn->local_tx_ctrl.cons, smc_curs_copy(&conn->rx_curs_confirmed, &curs, conn);
conn);
/* Calculate transmitted data and increment free send buffer space */ /* Calculate transmitted data and increment free send buffer space */
diff = smc_curs_diff(conn->sndbuf_desc->len, &conn->tx_curs_fin, diff = smc_curs_diff(conn->sndbuf_desc->len, &conn->tx_curs_fin,
&conn->tx_curs_sent); &conn->tx_curs_sent);
...@@ -331,13 +332,16 @@ static void smc_cdc_msg_recv(struct smc_sock *smc, struct smc_cdc_msg *cdc) ...@@ -331,13 +332,16 @@ static void smc_cdc_msg_recv(struct smc_sock *smc, struct smc_cdc_msg *cdc)
static void smcd_cdc_rx_tsklet(unsigned long data) static void smcd_cdc_rx_tsklet(unsigned long data)
{ {
struct smc_connection *conn = (struct smc_connection *)data; struct smc_connection *conn = (struct smc_connection *)data;
struct smcd_cdc_msg *data_cdc;
struct smcd_cdc_msg cdc; struct smcd_cdc_msg cdc;
struct smc_sock *smc; struct smc_sock *smc;
if (!conn) if (!conn)
return; return;
memcpy(&cdc, conn->rmb_desc->cpu_addr, sizeof(cdc)); data_cdc = (struct smcd_cdc_msg *)conn->rmb_desc->cpu_addr;
smcd_curs_copy(&cdc.prod, &data_cdc->prod, conn);
smcd_curs_copy(&cdc.cons, &data_cdc->cons, conn);
smc = container_of(conn, struct smc_sock, conn); smc = container_of(conn, struct smc_sock, conn);
smc_cdc_msg_recv(smc, (struct smc_cdc_msg *)&cdc); smc_cdc_msg_recv(smc, (struct smc_cdc_msg *)&cdc);
} }
......
...@@ -48,21 +48,31 @@ struct smc_cdc_msg { ...@@ -48,21 +48,31 @@ struct smc_cdc_msg {
struct smc_cdc_producer_flags prod_flags; struct smc_cdc_producer_flags prod_flags;
struct smc_cdc_conn_state_flags conn_state_flags; struct smc_cdc_conn_state_flags conn_state_flags;
u8 reserved[18]; u8 reserved[18];
} __packed; /* format defined in RFC7609 */ };
/* SMC-D cursor format */
union smcd_cdc_cursor {
struct {
u16 wrap;
u32 count;
struct smc_cdc_producer_flags prod_flags;
struct smc_cdc_conn_state_flags conn_state_flags;
} __packed;
#ifdef KERNEL_HAS_ATOMIC64
atomic64_t acurs; /* for atomic processing */
#else
u64 acurs; /* for atomic processing */
#endif
} __aligned(8);
/* CDC message for SMC-D */ /* CDC message for SMC-D */
struct smcd_cdc_msg { struct smcd_cdc_msg {
struct smc_wr_rx_hdr common; /* Type = 0xFE */ struct smc_wr_rx_hdr common; /* Type = 0xFE */
u8 res1[7]; u8 res1[7];
u16 prod_wrap; union smcd_cdc_cursor prod;
u32 prod_count; union smcd_cdc_cursor cons;
u8 res2[2];
u16 cons_wrap;
u32 cons_count;
struct smc_cdc_producer_flags prod_flags;
struct smc_cdc_conn_state_flags conn_state_flags;
u8 res3[8]; u8 res3[8];
} __packed; } __aligned(8);
static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn) static inline bool smc_cdc_rxed_any_close(struct smc_connection *conn)
{ {
...@@ -135,6 +145,21 @@ static inline void smc_curs_copy_net(union smc_cdc_cursor *tgt, ...@@ -135,6 +145,21 @@ static inline void smc_curs_copy_net(union smc_cdc_cursor *tgt,
#endif #endif
} }
static inline void smcd_curs_copy(union smcd_cdc_cursor *tgt,
union smcd_cdc_cursor *src,
struct smc_connection *conn)
{
#ifndef KERNEL_HAS_ATOMIC64
unsigned long flags;
spin_lock_irqsave(&conn->acurs_lock, flags);
tgt->acurs = src->acurs;
spin_unlock_irqrestore(&conn->acurs_lock, flags);
#else
atomic64_set(&tgt->acurs, atomic64_read(&src->acurs));
#endif
}
/* calculate cursor difference between old and new, where old <= new */ /* calculate cursor difference between old and new, where old <= new */
static inline int smc_curs_diff(unsigned int size, static inline int smc_curs_diff(unsigned int size,
union smc_host_cursor *old, union smc_host_cursor *old,
...@@ -222,12 +247,17 @@ static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local, ...@@ -222,12 +247,17 @@ static inline void smcr_cdc_msg_to_host(struct smc_host_cdc_msg *local,
static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local, static inline void smcd_cdc_msg_to_host(struct smc_host_cdc_msg *local,
struct smcd_cdc_msg *peer) struct smcd_cdc_msg *peer)
{ {
local->prod.wrap = peer->prod_wrap; union smc_host_cursor temp;
local->prod.count = peer->prod_count;
local->cons.wrap = peer->cons_wrap; temp.wrap = peer->prod.wrap;
local->cons.count = peer->cons_count; temp.count = peer->prod.count;
local->prod_flags = peer->prod_flags; atomic64_set(&local->prod.acurs, atomic64_read(&temp.acurs));
local->conn_state_flags = peer->conn_state_flags;
temp.wrap = peer->cons.wrap;
temp.count = peer->cons.count;
atomic64_set(&local->cons.acurs, atomic64_read(&temp.acurs));
local->prod_flags = peer->cons.prod_flags;
local->conn_state_flags = peer->cons.conn_state_flags;
} }
static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local, static inline void smc_cdc_msg_to_host(struct smc_host_cdc_msg *local,
......
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