1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved. 4 */ 5 6 #include <rdma/rdma_cm.h> 7 #include <rdma/ib_verbs.h> 8 #include <rdma/restrack.h> 9 #include <linux/mutex.h> 10 #include <linux/sched/task.h> 11 #include <linux/pid_namespace.h> 12 13 #include "cma_priv.h" 14 15 static int fill_res_noop(struct sk_buff *msg, 16 struct rdma_restrack_entry *entry) 17 { 18 return 0; 19 } 20 21 void rdma_restrack_init(struct rdma_restrack_root *res) 22 { 23 init_rwsem(&res->rwsem); 24 res->fill_res_entry = fill_res_noop; 25 } 26 27 static const char *type2str(enum rdma_restrack_type type) 28 { 29 static const char * const names[RDMA_RESTRACK_MAX] = { 30 [RDMA_RESTRACK_PD] = "PD", 31 [RDMA_RESTRACK_CQ] = "CQ", 32 [RDMA_RESTRACK_QP] = "QP", 33 [RDMA_RESTRACK_CM_ID] = "CM_ID", 34 [RDMA_RESTRACK_MR] = "MR", 35 }; 36 37 return names[type]; 38 }; 39 40 void rdma_restrack_clean(struct rdma_restrack_root *res) 41 { 42 struct rdma_restrack_entry *e; 43 char buf[TASK_COMM_LEN]; 44 struct ib_device *dev; 45 const char *owner; 46 int bkt; 47 48 if (hash_empty(res->hash)) 49 return; 50 51 dev = container_of(res, struct ib_device, res); 52 pr_err("restrack: %s", CUT_HERE); 53 dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n"); 54 hash_for_each(res->hash, bkt, e, node) { 55 if (rdma_is_kernel_res(e)) { 56 owner = e->kern_name; 57 } else { 58 /* 59 * There is no need to call get_task_struct here, 60 * because we can be here only if there are more 61 * get_task_struct() call than put_task_struct(). 62 */ 63 get_task_comm(buf, e->task); 64 owner = buf; 65 } 66 67 pr_err("restrack: %s %s object allocated by %s is not freed\n", 68 rdma_is_kernel_res(e) ? "Kernel" : "User", 69 type2str(e->type), owner); 70 } 71 pr_err("restrack: %s", CUT_HERE); 72 } 73 74 int rdma_restrack_count(struct rdma_restrack_root *res, 75 enum rdma_restrack_type type, 76 struct pid_namespace *ns) 77 { 78 struct rdma_restrack_entry *e; 79 u32 cnt = 0; 80 81 down_read(&res->rwsem); 82 hash_for_each_possible(res->hash, e, node, type) { 83 if (ns == &init_pid_ns || 84 (!rdma_is_kernel_res(e) && 85 ns == task_active_pid_ns(e->task))) 86 cnt++; 87 } 88 up_read(&res->rwsem); 89 return cnt; 90 } 91 EXPORT_SYMBOL(rdma_restrack_count); 92 93 static void set_kern_name(struct rdma_restrack_entry *res) 94 { 95 struct ib_pd *pd; 96 97 switch (res->type) { 98 case RDMA_RESTRACK_QP: 99 pd = container_of(res, struct ib_qp, res)->pd; 100 if (!pd) { 101 WARN_ONCE(true, "XRC QPs are not supported\n"); 102 /* Survive, despite the programmer's error */ 103 res->kern_name = " "; 104 } 105 break; 106 case RDMA_RESTRACK_MR: 107 pd = container_of(res, struct ib_mr, res)->pd; 108 break; 109 default: 110 /* Other types set kern_name directly */ 111 pd = NULL; 112 break; 113 } 114 115 if (pd) 116 res->kern_name = pd->res.kern_name; 117 } 118 119 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) 120 { 121 switch (res->type) { 122 case RDMA_RESTRACK_PD: 123 return container_of(res, struct ib_pd, res)->device; 124 case RDMA_RESTRACK_CQ: 125 return container_of(res, struct ib_cq, res)->device; 126 case RDMA_RESTRACK_QP: 127 return container_of(res, struct ib_qp, res)->device; 128 case RDMA_RESTRACK_CM_ID: 129 return container_of(res, struct rdma_id_private, 130 res)->id.device; 131 case RDMA_RESTRACK_MR: 132 return container_of(res, struct ib_mr, res)->device; 133 default: 134 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); 135 return NULL; 136 } 137 } 138 139 static bool res_is_user(struct rdma_restrack_entry *res) 140 { 141 switch (res->type) { 142 case RDMA_RESTRACK_PD: 143 return container_of(res, struct ib_pd, res)->uobject; 144 case RDMA_RESTRACK_CQ: 145 return container_of(res, struct ib_cq, res)->uobject; 146 case RDMA_RESTRACK_QP: 147 return container_of(res, struct ib_qp, res)->uobject; 148 case RDMA_RESTRACK_CM_ID: 149 return !res->kern_name; 150 case RDMA_RESTRACK_MR: 151 return container_of(res, struct ib_mr, res)->pd->uobject; 152 default: 153 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); 154 return false; 155 } 156 } 157 158 void rdma_restrack_set_task(struct rdma_restrack_entry *res, 159 const char *caller) 160 { 161 if (caller) { 162 res->kern_name = caller; 163 return; 164 } 165 166 if (res->task) 167 put_task_struct(res->task); 168 get_task_struct(current); 169 res->task = current; 170 } 171 EXPORT_SYMBOL(rdma_restrack_set_task); 172 173 void rdma_restrack_add(struct rdma_restrack_entry *res) 174 { 175 struct ib_device *dev = res_to_dev(res); 176 177 if (!dev) 178 return; 179 180 if (res->type != RDMA_RESTRACK_CM_ID || !res_is_user(res)) 181 res->task = NULL; 182 183 if (res_is_user(res)) { 184 if (!res->task) 185 rdma_restrack_set_task(res, NULL); 186 res->kern_name = NULL; 187 } else { 188 set_kern_name(res); 189 } 190 191 kref_init(&res->kref); 192 init_completion(&res->comp); 193 res->valid = true; 194 195 down_write(&dev->res.rwsem); 196 hash_add(dev->res.hash, &res->node, res->type); 197 up_write(&dev->res.rwsem); 198 } 199 EXPORT_SYMBOL(rdma_restrack_add); 200 201 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res) 202 { 203 return kref_get_unless_zero(&res->kref); 204 } 205 EXPORT_SYMBOL(rdma_restrack_get); 206 207 static void restrack_release(struct kref *kref) 208 { 209 struct rdma_restrack_entry *res; 210 211 res = container_of(kref, struct rdma_restrack_entry, kref); 212 complete(&res->comp); 213 } 214 215 int rdma_restrack_put(struct rdma_restrack_entry *res) 216 { 217 return kref_put(&res->kref, restrack_release); 218 } 219 EXPORT_SYMBOL(rdma_restrack_put); 220 221 void rdma_restrack_del(struct rdma_restrack_entry *res) 222 { 223 struct ib_device *dev; 224 225 if (!res->valid) 226 goto out; 227 228 dev = res_to_dev(res); 229 if (!dev) 230 return; 231 232 rdma_restrack_put(res); 233 234 wait_for_completion(&res->comp); 235 236 down_write(&dev->res.rwsem); 237 hash_del(&res->node); 238 res->valid = false; 239 up_write(&dev->res.rwsem); 240 241 out: 242 if (res->task) { 243 put_task_struct(res->task); 244 res->task = NULL; 245 } 246 } 247 EXPORT_SYMBOL(rdma_restrack_del); 248