rds: Fix RDMA message reference counting
authorChris Mason <chris.mason@oracle.com>
Tue, 11 May 2010 22:14:16 +0000 (15:14 -0700)
committerAndy Grover <andy.grover@oracle.com>
Thu, 9 Sep 2010 01:15:10 +0000 (18:15 -0700)
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>
net/rds/ib_send.c
net/rds/send.c

index 657037d96cbf7ec3228ff6105306827061e8dd99..82459e52c77110536aca49dee3bdecce35f68aba 100644 (file)
@@ -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;
                        }
index d35c43ff792e70ed56dfa1bd372f791638bf921b..5c6d4a0be0d7dbca253a9bb27087154e8909909a 100644 (file)
@@ -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.