| From 1feb40067cf04ae48d65f728d62ca255c9449178 Mon Sep 17 00:00:00 2001 |
| From: Mike Marciniszyn <mike.marciniszyn@intel.com> |
| Date: Fri, 12 May 2017 09:02:00 -0700 |
| Subject: RDMA/qib,hfi1: Fix MR reference count leak on write with immediate |
| |
| From: Mike Marciniszyn <mike.marciniszyn@intel.com> |
| |
| commit 1feb40067cf04ae48d65f728d62ca255c9449178 upstream. |
| |
| The handling of IB_RDMA_WRITE_ONLY_WITH_IMMEDIATE will leak a memory |
| reference when a buffer cannot be allocated for returning the immediate |
| data. |
| |
| The issue is that the rkey validation has already occurred and the RNR |
| nak fails to release the reference that was fruitlessly gotten. The |
| the peer will send the identical single packet request when its RNR |
| timer pops. |
| |
| The fix is to release the held reference prior to the rnr nak exit. |
| This is the only sequence the requires both rkey validation and the |
| buffer allocation on the same packet. |
| |
| Tested-by: Tadeusz Struk <tadeusz.struk@intel.com> |
| Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com> |
| Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com> |
| Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com> |
| Signed-off-by: Doug Ledford <dledford@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/infiniband/hw/hfi1/rc.c | 5 ++++- |
| drivers/infiniband/hw/qib/qib_rc.c | 4 +++- |
| 2 files changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/infiniband/hw/hfi1/rc.c |
| +++ b/drivers/infiniband/hw/hfi1/rc.c |
| @@ -2366,8 +2366,11 @@ send_last: |
| ret = hfi1_rvt_get_rwqe(qp, 1); |
| if (ret < 0) |
| goto nack_op_err; |
| - if (!ret) |
| + if (!ret) { |
| + /* peer will send again */ |
| + rvt_put_ss(&qp->r_sge); |
| goto rnr_nak; |
| + } |
| wc.ex.imm_data = ohdr->u.rc.imm_data; |
| wc.wc_flags = IB_WC_WITH_IMM; |
| goto send_last; |
| --- a/drivers/infiniband/hw/qib/qib_rc.c |
| +++ b/drivers/infiniband/hw/qib/qib_rc.c |
| @@ -2067,8 +2067,10 @@ send_last: |
| ret = qib_get_rwqe(qp, 1); |
| if (ret < 0) |
| goto nack_op_err; |
| - if (!ret) |
| + if (!ret) { |
| + rvt_put_ss(&qp->r_sge); |
| goto rnr_nak; |
| + } |
| wc.ex.imm_data = ohdr->u.rc.imm_data; |
| hdrsize += 4; |
| wc.wc_flags = IB_WC_WITH_IMM; |