aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIra Weiny <ira.weiny@intel.com>2016-07-28 15:21:26 -0400
committerDoug Ledford <dledford@redhat.com>2016-08-02 22:46:21 -0400
commit2677a7680e773195a4fdabd163d756cac1b9abd7 (patch)
treed8640d01378b5d7ffa798f00cbcd29d686d9a1d4
parent082b3532915395ea6620ba691138baf151a543b0 (diff)
IB/hfi1: Fix memory leak during unexpected shutdown
During an unexpected shutdown, references to tid_rb_node were NULL'ed out without properly being released. Fix this by calling clear_tid_node in the mmu notifier remove callback rather than after these callbacks are called. Reviewed-by: Dean Luick <dean.luick@intel.com> Signed-off-by: Ira Weiny <ira.weiny@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r--drivers/infiniband/hw/hfi1/user_exp_rcv.c44
1 files changed, 31 insertions, 13 deletions
diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c
index 8717e11fe3f5..64d26525435a 100644
--- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c
+++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c
@@ -87,13 +87,15 @@ static u32 find_phys_blocks(struct page **, unsigned, struct tid_pageset *);
87static int set_rcvarray_entry(struct file *, unsigned long, u32, 87static int set_rcvarray_entry(struct file *, unsigned long, u32,
88 struct tid_group *, struct page **, unsigned); 88 struct tid_group *, struct page **, unsigned);
89static int tid_rb_insert(void *, struct mmu_rb_node *); 89static int tid_rb_insert(void *, struct mmu_rb_node *);
90static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata,
91 struct tid_rb_node *tnode);
90static void tid_rb_remove(void *, struct mmu_rb_node *); 92static void tid_rb_remove(void *, struct mmu_rb_node *);
91static int tid_rb_invalidate(void *, struct mmu_rb_node *); 93static int tid_rb_invalidate(void *, struct mmu_rb_node *);
92static int program_rcvarray(struct file *, unsigned long, struct tid_group *, 94static int program_rcvarray(struct file *, unsigned long, struct tid_group *,
93 struct tid_pageset *, unsigned, u16, struct page **, 95 struct tid_pageset *, unsigned, u16, struct page **,
94 u32 *, unsigned *, unsigned *); 96 u32 *, unsigned *, unsigned *);
95static int unprogram_rcvarray(struct file *, u32, struct tid_group **); 97static int unprogram_rcvarray(struct file *, u32, struct tid_group **);
96static void clear_tid_node(struct hfi1_filedata *, struct tid_rb_node *); 98static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node);
97 99
98static struct mmu_rb_ops tid_rb_ops = { 100static struct mmu_rb_ops tid_rb_ops = {
99 .insert = tid_rb_insert, 101 .insert = tid_rb_insert,
@@ -899,14 +901,15 @@ static int unprogram_rcvarray(struct file *fp, u32 tidinfo,
899 node = fd->entry_to_rb[rcventry]; 901 node = fd->entry_to_rb[rcventry];
900 if (!node || node->rcventry != (uctxt->expected_base + rcventry)) 902 if (!node || node->rcventry != (uctxt->expected_base + rcventry))
901 return -EBADF; 903 return -EBADF;
904
905 if (grp)
906 *grp = node->grp;
907
902 if (!fd->handler) 908 if (!fd->handler)
903 tid_rb_remove(fd, &node->mmu); 909 cacheless_tid_rb_remove(fd, node);
904 else 910 else
905 hfi1_mmu_rb_remove(fd->handler, &node->mmu); 911 hfi1_mmu_rb_remove(fd->handler, &node->mmu);
906 912
907 if (grp)
908 *grp = node->grp;
909 clear_tid_node(fd, node);
910 return 0; 913 return 0;
911} 914}
912 915
@@ -943,6 +946,10 @@ static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
943 kfree(node); 946 kfree(node);
944} 947}
945 948
949/*
950 * As a simple helper for hfi1_user_exp_rcv_free, this function deals with
951 * clearing nodes in the non-cached case.
952 */
946static void unlock_exp_tids(struct hfi1_ctxtdata *uctxt, 953static void unlock_exp_tids(struct hfi1_ctxtdata *uctxt,
947 struct exp_tid_set *set, 954 struct exp_tid_set *set,
948 struct hfi1_filedata *fd) 955 struct hfi1_filedata *fd)
@@ -962,17 +969,20 @@ static void unlock_exp_tids(struct hfi1_ctxtdata *uctxt,
962 uctxt->expected_base]; 969 uctxt->expected_base];
963 if (!node || node->rcventry != rcventry) 970 if (!node || node->rcventry != rcventry)
964 continue; 971 continue;
965 if (!fd->handler) 972
966 tid_rb_remove(fd, &node->mmu); 973 cacheless_tid_rb_remove(fd, node);
967 else
968 hfi1_mmu_rb_remove(fd->handler,
969 &node->mmu);
970 clear_tid_node(fd, node);
971 } 974 }
972 } 975 }
973 } 976 }
974} 977}
975 978
979/*
980 * Always return 0 from this function. A non-zero return indicates that the
981 * remove operation will be called and that memory should be unpinned.
982 * However, the driver cannot unpin out from under PSM. Instead, retain the
983 * memory (by returning 0) and inform PSM that the memory is going away. PSM
984 * will call back later when it has removed the memory from its list.
985 */
976static int tid_rb_invalidate(void *arg, struct mmu_rb_node *mnode) 986static int tid_rb_invalidate(void *arg, struct mmu_rb_node *mnode)
977{ 987{
978 struct hfi1_filedata *fdata = arg; 988 struct hfi1_filedata *fdata = arg;
@@ -1027,12 +1037,20 @@ static int tid_rb_insert(void *arg, struct mmu_rb_node *node)
1027 return 0; 1037 return 0;
1028} 1038}
1029 1039
1040static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata,
1041 struct tid_rb_node *tnode)
1042{
1043 u32 base = fdata->uctxt->expected_base;
1044
1045 fdata->entry_to_rb[tnode->rcventry - base] = NULL;
1046 clear_tid_node(fdata, tnode);
1047}
1048
1030static void tid_rb_remove(void *arg, struct mmu_rb_node *node) 1049static void tid_rb_remove(void *arg, struct mmu_rb_node *node)
1031{ 1050{
1032 struct hfi1_filedata *fdata = arg; 1051 struct hfi1_filedata *fdata = arg;
1033 struct tid_rb_node *tnode = 1052 struct tid_rb_node *tnode =
1034 container_of(node, struct tid_rb_node, mmu); 1053 container_of(node, struct tid_rb_node, mmu);
1035 u32 base = fdata->uctxt->expected_base;
1036 1054
1037 fdata->entry_to_rb[tnode->rcventry - base] = NULL; 1055 cacheless_tid_rb_remove(fdata, tnode);
1038} 1056}