IB/srp: Fix srp_map_data() error paths
authorBart Van Assche <bart.vanassche@sandisk.com>
Fri, 22 Apr 2016 21:13:35 +0000 (14:13 -0700)
committerDoug Ledford <dledford@redhat.com>
Thu, 12 May 2016 18:18:55 +0000 (14:18 -0400)
Ensure that req->nmdesc is set correctly in srp_map_sg() if mapping
fails. Avoid that mapping failure causes a memory descriptor leak.
Report srp_map_sg() failure to the caller.

Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Sagi Grimberg <sagi@grimberg.me>
Cc: Laurence Oberman <loberman@redhat.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/ulp/srp/ib_srp.c

index 269f5ebe82de253bbf355d5ad92cecc8b66c1f55..47e753d9ab5b68e86d5127a5aa145f7c2fe61837 100644 (file)
@@ -1428,8 +1428,6 @@ static int srp_map_sg_fmr(struct srp_map_state *state, struct srp_rdma_ch *ch,
        if (ret)
                return ret;
 
-       req->nmdesc = state->nmdesc;
-
        return 0;
 }
 
@@ -1454,8 +1452,6 @@ static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch,
                        state->sg = sg_next(state->sg);
        }
 
-       req->nmdesc = state->nmdesc;
-
        return 0;
 }
 
@@ -1475,8 +1471,6 @@ static int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch,
                             target->global_mr->rkey);
        }
 
-       req->nmdesc = state->nmdesc;
-
        return 0;
 }
 
@@ -1610,11 +1604,14 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
 
        memset(&state, 0, sizeof(state));
        if (dev->use_fast_reg)
-               srp_map_sg_fr(&state, ch, req, scat, count);
+               ret = srp_map_sg_fr(&state, ch, req, scat, count);
        else if (dev->use_fmr)
-               srp_map_sg_fmr(&state, ch, req, scat, count);
+               ret = srp_map_sg_fmr(&state, ch, req, scat, count);
        else
-               srp_map_sg_dma(&state, ch, req, scat, count);
+               ret = srp_map_sg_dma(&state, ch, req, scat, count);
+       req->nmdesc = state.nmdesc;
+       if (ret < 0)
+               goto unmap;
 
        /* We've mapped the request, now pull as much of the indirect
         * descriptor table as we can into the command buffer. If this
@@ -1637,7 +1634,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
                                                !target->allow_ext_sg)) {
                shost_printk(KERN_ERR, target->scsi_host,
                             "Could not fit S/G list into SRP_CMD\n");
-               return -EIO;
+               ret = -EIO;
+               goto unmap;
        }
 
        count = min(state.ndesc, target->cmd_sg_cnt);
@@ -1655,7 +1653,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
                ret = srp_map_idb(ch, req, state.gen.next, state.gen.end,
                                  idb_len, &idb_rkey);
                if (ret < 0)
-                       return ret;
+                       goto unmap;
                req->nmdesc++;
        } else {
                idb_rkey = cpu_to_be32(target->global_mr->rkey);
@@ -1681,6 +1679,10 @@ map_complete:
                cmd->buf_fmt = fmt;
 
        return len;
+
+unmap:
+       srp_unmap_data(scmnd, ch, req);
+       return ret;
 }
 
 /*