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