IB/hfi1: Fix a potential memory leak in hfi1_create_ctxts()
authorJianxin Xiong <jianxin.xiong@intel.com>
Mon, 17 Oct 2016 11:19:41 +0000 (04:19 -0700)
committerDoug Ledford <dledford@redhat.com>
Tue, 15 Nov 2016 21:16:42 +0000 (16:16 -0500)
In the function hfi1_create_ctxts the array "dd->rcd" is allocated and
then populated with allocated resources in a loop. Previously, if
error happened during the loop, only resource allocated in the current
iteration would be freed. The array itself would then be freed, leaving
the resources that were allocated in previous iterations and referenced
by the array elements in limbo.

This patch makes sure all allocated resources are freed before freeing
the array "dd->rcd". Also the resource allocation now takes account of
the numa node the device is attached to.

Reviewed-by: Tadeusz Struk <tadeusz.struk@intel.com>
Signed-off-by: Jianxin Xiong <jianxin.xiong@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/hfi1/init.c

index baea53f..e27b65d 100644 (file)
@@ -144,6 +144,8 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
                struct hfi1_ctxtdata *rcd;
 
                ppd = dd->pport + (i % dd->num_pports);
+
+               /* dd->rcd[i] gets assigned inside the callee */
                rcd = hfi1_create_ctxtdata(ppd, i, dd->node);
                if (!rcd) {
                        dd_dev_err(dd,
@@ -169,8 +171,6 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
                if (!rcd->sc) {
                        dd_dev_err(dd,
                                   "Unable to allocate kernel send context, failing\n");
-                       dd->rcd[rcd->ctxt] = NULL;
-                       hfi1_free_ctxtdata(dd, rcd);
                        goto nomem;
                }
 
@@ -178,9 +178,6 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
                if (ret < 0) {
                        dd_dev_err(dd,
                                   "Failed to setup kernel receive context, failing\n");
-                       sc_free(rcd->sc);
-                       dd->rcd[rcd->ctxt] = NULL;
-                       hfi1_free_ctxtdata(dd, rcd);
                        ret = -EFAULT;
                        goto bail;
                }
@@ -196,6 +193,10 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)
 nomem:
        ret = -ENOMEM;
 bail:
+       if (dd->rcd) {
+               for (i = 0; i < dd->num_rcv_contexts; ++i)
+                       hfi1_free_ctxtdata(dd, dd->rcd[i]);
+       }
        kfree(dd->rcd);
        dd->rcd = NULL;
        return ret;
@@ -216,7 +217,7 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt,
            dd->num_rcv_contexts - dd->first_user_ctxt)
                kctxt_ngroups = (dd->rcv_entries.nctxt_extra -
                                 (dd->num_rcv_contexts - dd->first_user_ctxt));
-       rcd = kzalloc(sizeof(*rcd), GFP_KERNEL);
+       rcd = kzalloc_node(sizeof(*rcd), GFP_KERNEL, numa);
        if (rcd) {
                u32 rcvtids, max_entries;