summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2010-05-11 22:14:16 (GMT)
committerAndy Grover <andy.grover@oracle.com>2010-09-09 01:15:10 (GMT)
commitc9e65383a20d9a656db70efbf67e57f8115ad776 (patch)
tree3055f38ada5a60e858fe66e12353cad37e8ebdd5
parent7e3f2952eeb1a0fe2aa9882fd1705a88f9d89b35 (diff)
downloadlinux-c9e65383a20d9a656db70efbf67e57f8115ad776.tar.xz
rds: Fix RDMA message reference counting
The RDS send_xmit code was trying to get fancy with message counting and was dropping the final reference on the RDMA messages too early. This resulted in memory corruption and oopsen. The fix here is to always add a ref as the parts of the message passes through rds_send_xmit, and always drop a ref as the parts of the message go through completion handling. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--net/rds/ib_send.c11
-rw-r--r--net/rds/send.c11
2 files changed, 14 insertions, 8 deletions
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c
index 657037d..82459e5 100644
--- a/net/rds/ib_send.c
+++ b/net/rds/ib_send.c
@@ -268,11 +268,12 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
if (send->s_queued + HZ/2 < jiffies)
rds_ib_stats_inc(s_ib_tx_stalled);
- if (&send->s_op == &rm->m_final_op) {
- /* If anyone waited for this message to get flushed out, wake
- * them up now */
- rds_message_unmapped(rm);
-
+ if (send->s_op) {
+ if (send->s_op == rm->m_final_op) {
+ /* If anyone waited for this message to get flushed out, wake
+ * them up now */
+ rds_message_unmapped(rm);
+ }
rds_message_put(rm);
send->s_op = NULL;
}
diff --git a/net/rds/send.c b/net/rds/send.c
index d35c43f..5c6d4a0 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -68,7 +68,6 @@ void rds_send_reset(struct rds_connection *conn)
* transport. This isn't entirely true (it's flushed out
* independently) but as the connection is down, there's
* no ongoing RDMA to/from that memory */
-printk(KERN_CRIT "send reset unmapping %p\n", rm);
rds_message_unmapped(rm);
spin_unlock_irqrestore(&conn->c_send_lock, flags);
@@ -234,10 +233,13 @@ restart:
/* The transport either sends the whole rdma or none of it */
if (rm->rdma.op_active && !conn->c_xmit_rdma_sent) {
+ rds_message_addref(rm);
rm->m_final_op = &rm->rdma;
ret = conn->c_trans->xmit_rdma(conn, &rm->rdma);
- if (ret)
+ if (ret) {
+ rds_message_put(rm);
break;
+ }
conn->c_xmit_rdma_sent = 1;
/* The transport owns the mapped memory for now.
@@ -246,10 +248,13 @@ restart:
}
if (rm->atomic.op_active && !conn->c_xmit_atomic_sent) {
+ rds_message_addref(rm);
rm->m_final_op = &rm->atomic;
ret = conn->c_trans->xmit_atomic(conn, &rm->atomic);
- if (ret)
+ if (ret) {
+ rds_message_put(rm);
break;
+ }
conn->c_xmit_atomic_sent = 1;
/* The transport owns the mapped memory for now.