Commit 4cbd5018 authored by Michael J. Ruhl's avatar Michael J. Ruhl Committed by Greg Kroah-Hartman

IB/hfi1: Fix a subcontext memory leak

commit 224d71f9 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: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: default avatarMichael J. Ruhl <michael.j.ruhl@intel.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d971ab21
...@@ -752,6 +752,9 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) ...@@ -752,6 +752,9 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
/* release the cpu */ /* release the cpu */
hfi1_put_proc_affinity(fdata->rec_cpu_num); 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 * Clear any left over, unhandled events so the next process that
* gets this context doesn't get confused. * gets this context doesn't get confused.
...@@ -791,7 +794,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) ...@@ -791,7 +794,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp)
dd->rcd[uctxt->ctxt] = NULL; 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); hfi1_clear_ctxt_pkey(dd, uctxt->ctxt);
uctxt->rcvwait_to = 0; uctxt->rcvwait_to = 0;
......
...@@ -251,36 +251,40 @@ int hfi1_user_exp_rcv_init(struct file *fp) ...@@ -251,36 +251,40 @@ int hfi1_user_exp_rcv_init(struct file *fp)
return ret; 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) int hfi1_user_exp_rcv_free(struct hfi1_filedata *fd)
{ {
struct hfi1_ctxtdata *uctxt = fd->uctxt; 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 * The notifier would have been removed when the process'es mm
* was freed. * was freed.
*/ */
if (fd->handler) if (fd->handler) {
hfi1_mmu_rb_unregister(fd->handler); hfi1_mmu_rb_unregister(fd->handler);
} else {
kfree(fd->invalid_tids);
if (!uctxt->cnt) {
if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list)) if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list))
unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd); unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd);
if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list)) if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list))
unlock_exp_tids(uctxt, &uctxt->tid_used_list, fd); 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); kfree(fd->entry_to_rb);
fd->entry_to_rb = NULL;
return 0; return 0;
} }
......
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
(tid) |= EXP_TID_SET(field, (value)); \ (tid) |= EXP_TID_SET(field, (value)); \
} while (0) } 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_init(struct file *);
int hfi1_user_exp_rcv_free(struct hfi1_filedata *); int hfi1_user_exp_rcv_free(struct hfi1_filedata *);
int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *); int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment