diff options
author | Michael J. Ruhl <michael.j.ruhl@intel.com> | 2017-05-04 08:14:34 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-25 09:44:38 -0400 |
commit | 5e40ac3fbd0d733bf32447b44f50ca32efb05e20 (patch) | |
tree | 8c5b1cb6b7dd47c53fa8928650e9be84d39dc537 /drivers/infiniband | |
parent | b894ea8263caee43d90c2f956361f280bc32990d (diff) |
IB/hfi1: Fix a subcontext memory leak
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.marciniszyn@intel.com>
Signed-off-by: Michael J. Ruhl <michael.j.ruhl@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>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/hfi1/file_ops.c | 5 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/user_exp_rcv.c | 32 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/user_exp_rcv.h | 1 |
3 files changed, 23 insertions, 15 deletions
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index bd786b7bd30b..bb729764a799 100644 --- 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 *inode, struct file *fp) | |||
751 | /* release the cpu */ | 751 | /* release the cpu */ |
752 | hfi1_put_proc_affinity(fdata->rec_cpu_num); | 752 | hfi1_put_proc_affinity(fdata->rec_cpu_num); |
753 | 753 | ||
754 | /* clean up rcv side */ | ||
755 | hfi1_user_exp_rcv_free(fdata); | ||
756 | |||
754 | /* | 757 | /* |
755 | * Clear any left over, unhandled events so the next process that | 758 | * Clear any left over, unhandled events so the next process that |
756 | * gets this context doesn't get confused. | 759 | * gets this context doesn't get confused. |
@@ -790,7 +793,7 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) | |||
790 | 793 | ||
791 | dd->rcd[uctxt->ctxt] = NULL; | 794 | dd->rcd[uctxt->ctxt] = NULL; |
792 | 795 | ||
793 | hfi1_user_exp_rcv_free(fdata); | 796 | hfi1_user_exp_rcv_grp_free(uctxt); |
794 | hfi1_clear_ctxt_pkey(dd, uctxt->ctxt); | 797 | hfi1_clear_ctxt_pkey(dd, uctxt->ctxt); |
795 | 798 | ||
796 | uctxt->rcvwait_to = 0; | 799 | uctxt->rcvwait_to = 0; |
diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c index 64d26525435a..db0f140e2116 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c | |||
@@ -250,36 +250,40 @@ done: | |||
250 | return ret; | 250 | return ret; |
251 | } | 251 | } |
252 | 252 | ||
253 | void hfi1_user_exp_rcv_grp_free(struct hfi1_ctxtdata *uctxt) | ||
254 | { | ||
255 | struct tid_group *grp, *gptr; | ||
256 | |||
257 | list_for_each_entry_safe(grp, gptr, &uctxt->tid_group_list.list, | ||
258 | list) { | ||
259 | list_del_init(&grp->list); | ||
260 | kfree(grp); | ||
261 | } | ||
262 | hfi1_clear_tids(uctxt); | ||
263 | } | ||
264 | |||
253 | int hfi1_user_exp_rcv_free(struct hfi1_filedata *fd) | 265 | int hfi1_user_exp_rcv_free(struct hfi1_filedata *fd) |
254 | { | 266 | { |
255 | struct hfi1_ctxtdata *uctxt = fd->uctxt; | 267 | struct hfi1_ctxtdata *uctxt = fd->uctxt; |
256 | struct tid_group *grp, *gptr; | ||
257 | 268 | ||
258 | if (!test_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags)) | ||
259 | return 0; | ||
260 | /* | 269 | /* |
261 | * The notifier would have been removed when the process'es mm | 270 | * The notifier would have been removed when the process'es mm |
262 | * was freed. | 271 | * was freed. |
263 | */ | 272 | */ |
264 | if (fd->handler) | 273 | if (fd->handler) { |
265 | hfi1_mmu_rb_unregister(fd->handler); | 274 | hfi1_mmu_rb_unregister(fd->handler); |
266 | 275 | } else { | |
267 | kfree(fd->invalid_tids); | ||
268 | |||
269 | if (!uctxt->cnt) { | ||
270 | if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list)) | 276 | if (!EXP_TID_SET_EMPTY(uctxt->tid_full_list)) |
271 | unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd); | 277 | unlock_exp_tids(uctxt, &uctxt->tid_full_list, fd); |
272 | if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list)) | 278 | if (!EXP_TID_SET_EMPTY(uctxt->tid_used_list)) |
273 | unlock_exp_tids(uctxt, &uctxt->tid_used_list, fd); | 279 | unlock_exp_tids(uctxt, &uctxt->tid_used_list, fd); |
274 | list_for_each_entry_safe(grp, gptr, &uctxt->tid_group_list.list, | ||
275 | list) { | ||
276 | list_del_init(&grp->list); | ||
277 | kfree(grp); | ||
278 | } | ||
279 | hfi1_clear_tids(uctxt); | ||
280 | } | 280 | } |
281 | 281 | ||
282 | kfree(fd->invalid_tids); | ||
283 | fd->invalid_tids = NULL; | ||
284 | |||
282 | kfree(fd->entry_to_rb); | 285 | kfree(fd->entry_to_rb); |
286 | fd->entry_to_rb = NULL; | ||
283 | return 0; | 287 | return 0; |
284 | } | 288 | } |
285 | 289 | ||
diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.h b/drivers/infiniband/hw/hfi1/user_exp_rcv.h index 9bc8d9fba87e..d1d7d3d3bd44 100644 --- a/drivers/infiniband/hw/hfi1/user_exp_rcv.h +++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.h | |||
@@ -70,6 +70,7 @@ | |||
70 | (tid) |= EXP_TID_SET(field, (value)); \ | 70 | (tid) |= EXP_TID_SET(field, (value)); \ |
71 | } while (0) | 71 | } while (0) |
72 | 72 | ||
73 | void hfi1_user_exp_rcv_grp_free(struct hfi1_ctxtdata *uctxt); | ||
73 | int hfi1_user_exp_rcv_init(struct file *); | 74 | int hfi1_user_exp_rcv_init(struct file *); |
74 | int hfi1_user_exp_rcv_free(struct hfi1_filedata *); | 75 | int hfi1_user_exp_rcv_free(struct hfi1_filedata *); |
75 | int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *); | 76 | int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *); |