From 3977026462314dfbb237adf6a964d0f683b8e45d Mon Sep 17 00:00:00 2001 From: Bryan O'Sullivan Date: Tue, 23 May 2006 11:32:37 -0700 Subject: [PATCH] IB/ipath: fix null deref during rdma ops 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 Signed-off-by: Bryan O'Sullivan Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ipath/ipath_layer.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c index 9cb5258ffed..9ec4ac77b87 100644 --- a/drivers/infiniband/hw/ipath/ipath_layer.c +++ b/drivers/infiniband/hw/ipath/ipath_layer.c @@ -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; } -- 2.41.0