4.9-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Michael J. Ruhl <michael.j.r...@intel.com>

commit 224d71f910102c966cdcd782c97e096d5e26e4da upstream.

The only context that frees user_exp_rcv data structures is the last
context closed (from a sub-context set).  This leaks the allocations
from the other sub-contexts.  Separate the common frees from the
specific frees and call them at the appropriate time.

Using KEDR to check for memory leaks we get:

Before test:

[leak_check] Possible leaks: 25

After test:

[leak_check] Possible leaks: 31  (6 leaked data structures)

After patch applied (before and after test have the same value)

[leak_check] Possible leaks: 25

Each leak is 192 + 13440 + 6720 = 20352 bytes per sub-context.

Reviewed-by: Mike Marciniszyn <mike.marcinis...@intel.com>
Signed-off-by: Michael J. Ruhl <michael.j.r...@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessan...@intel.com>
Signed-off-by: Doug Ledford <dledf...@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/infiniband/hw/hfi1/file_ops.c     |    5 +++-
 drivers/infiniband/hw/hfi1/user_exp_rcv.c |   32 ++++++++++++++++--------------
 drivers/infiniband/hw/hfi1/user_exp_rcv.h |    1 
 3 files changed, 23 insertions(+), 15 deletions(-)

--- a/drivers/infiniband/hw/hfi1/file_ops.c
+++ b/drivers/infiniband/hw/hfi1/file_ops.c
@@ -751,6 +751,9 @@ static int hfi1_file_close(struct inode
        /* release the cpu */
        hfi1_put_proc_affinity(fdata->rec_cpu_num);
 
+       /* clean up rcv side */
+       hfi1_user_exp_rcv_free(fdata);
+
        /*
         * Clear any left over, unhandled events so the next process that
         * gets this context doesn't get confused.
@@ -790,7 +793,7 @@ static int hfi1_file_close(struct inode
 
        dd->rcd[uctxt->ctxt] = NULL;
 
-       hfi1_user_exp_rcv_free(fdata);
+       hfi1_user_exp_rcv_grp_free(uctxt);
        hfi1_clear_ctxt_pkey(dd, uctxt->ctxt);
 
        uctxt->rcvwait_to = 0;
--- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c
+++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c
@@ -250,36 +250,40 @@ done:
        return ret;
 }
 
+void hfi1_user_exp_rcv_grp_free(struct hfi1_ctxtdata *uctxt)
+{
+       struct tid_group *grp, *gptr;
+
+       list_for_each_entry_safe(grp, gptr, &uctxt->tid_group_list.list,
+                                list) {
+               list_del_init(&grp->list);
+               kfree(grp);
+       }
+       hfi1_clear_tids(uctxt);
+}
+
 int hfi1_user_exp_rcv_free(struct hfi1_filedata *fd)
 {
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
-       struct tid_group *grp, *gptr;
 
-       if (!test_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags))
-               return 0;
        /*
         * The notifier would have been removed when the process'es mm
         * was freed.
         */
-       if (fd->handler)
+       if (fd->handler) {
                hfi1_mmu_rb_unregister(fd->handler);
-
-       kfree(fd->invalid_tids);
-
-       if (!uctxt->cnt) {
+       } else {
                if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list))
                        unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd);
                if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list))
                        unlock_exp_tids(uctxt, &uctxt->tid_used_list, fd);
-               list_for_each_entry_safe(grp, gptr, &uctxt->tid_group_list.list,
-                                        list) {
-                       list_del_init(&grp->list);
-                       kfree(grp);
-               }
-               hfi1_clear_tids(uctxt);
        }
 
+       kfree(fd->invalid_tids);
+       fd->invalid_tids = NULL;
+
        kfree(fd->entry_to_rb);
+       fd->entry_to_rb = NULL;
        return 0;
 }
 
--- a/drivers/infiniband/hw/hfi1/user_exp_rcv.h
+++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.h
@@ -70,6 +70,7 @@
                (tid) |= EXP_TID_SET(field, (value));                   \
        } while (0)
 
+void hfi1_user_exp_rcv_grp_free(struct hfi1_ctxtdata *uctxt);
 int hfi1_user_exp_rcv_init(struct file *);
 int hfi1_user_exp_rcv_free(struct hfi1_filedata *);
 int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *);


Reply via email to