aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorMichael J. Ruhl <michael.j.ruhl@intel.com>2017-05-04 08:14:34 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-25 09:44:38 -0400
commit5e40ac3fbd0d733bf32447b44f50ca32efb05e20 (patch)
tree8c5b1cb6b7dd47c53fa8928650e9be84d39dc537 /drivers/infiniband
parentb894ea8263caee43d90c2f956361f280bc32990d (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.c5
-rw-r--r--drivers/infiniband/hw/hfi1/user_exp_rcv.c32
-rw-r--r--drivers/infiniband/hw/hfi1/user_exp_rcv.h1
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
253void 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
253int hfi1_user_exp_rcv_free(struct hfi1_filedata *fd) 265int 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
73void hfi1_user_exp_rcv_grp_free(struct hfi1_ctxtdata *uctxt);
73int hfi1_user_exp_rcv_init(struct file *); 74int hfi1_user_exp_rcv_init(struct file *);
74int hfi1_user_exp_rcv_free(struct hfi1_filedata *); 75int hfi1_user_exp_rcv_free(struct hfi1_filedata *);
75int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *); 76int hfi1_user_exp_rcv_setup(struct file *, struct hfi1_tid_info *);