IB/ipath: fix null deref during rdma ops
authorBryan O'Sullivan <bos@pathscale.com>
Tue, 23 May 2006 18:32:37 +0000 (11:32 -0700)
committerRoland Dreier <rolandd@cisco.com>
Tue, 23 May 2006 20:29:35 +0000 (13:29 -0700)
The problem was that node A's sending thread, which handles sending RDMA
read response data, would write the trigger word, the last packet would
be sent, node B would send a new RDMA read request, node A's interrupt
handler would initialize s_rdma_sge, then node A's sending thread would
update s_rdma_sge.  This didn't happen very often naturally but was more
frequent with 1 byte RDMA reads.  Rather than adding more locking or
increasing the QP structure size and copying sge data, I modified the
copy routine to update the pointers before writing the trigger word to
avoid the update race.

Signed-off-by: Ralph Campbell <ralphc@pathscale.com>
Signed-off-by: Bryan O'Sullivan <bos@pathscale.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/ipath/ipath_layer.c

index 9cb5258ffed95330f9f739100840c139588c3d33..9ec4ac77b87f88df622d5b1d3bc3acf421d3c9b1 100644 (file)
@@ -872,12 +872,13 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
                update_sge(ss, len);
                length -= len;
        }
+       /* Update address before sending packet. */
+       update_sge(ss, length);
        /* must flush early everything before trigger word */
        ipath_flush_wc();
        __raw_writel(last, piobuf);
        /* be sure trigger word is written */
        ipath_flush_wc();
-       update_sge(ss, length);
 }
 
 /**
@@ -943,17 +944,18 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
        if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
                   !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
                u32 w;
+               u32 *addr = (u32 *) ss->sge.vaddr;
 
+               /* Update address before sending packet. */
+               update_sge(ss, len);
                /* Need to round up for the last dword in the packet. */
                w = (len + 3) >> 2;
-               __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1);
+               __iowrite32_copy(piobuf, addr, w - 1);
                /* must flush early everything before trigger word */
                ipath_flush_wc();
-               __raw_writel(((u32 *) ss->sge.vaddr)[w - 1],
-                            piobuf + w - 1);
+               __raw_writel(addr[w - 1], piobuf + w - 1);
                /* be sure trigger word is written */
                ipath_flush_wc();
-               update_sge(ss, len);
                ret = 0;
                goto bail;
        }