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 pr_err("restrack: BUG: RESTRACK detected leak of resources on %s\n", 54 dev->name); 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 default: 135 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); 136 return NULL; 137 } 138 } 139 140 static bool res_is_user(struct rdma_restrack_entry *res) 141 { 142 switch (res->type) { 143 case RDMA_RESTRACK_PD: 144 return container_of(res, struct ib_pd, res)->uobject; 145 case RDMA_RESTRACK_CQ: 146 return container_of(res, struct ib_cq, res)->uobject; 147 case RDMA_RESTRACK_QP: 148 return container_of(res, struct ib_qp, res)->uobject; 149 case RDMA_RESTRACK_CM_ID: 150 return !res->kern_name; 151 case RDMA_RESTRACK_MR: 152 return container_of(res, struct ib_mr, res)->pd->uobject; 153 default: 154 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); 155 return false; 156 } 157 } 158 159 void rdma_restrack_add(struct rdma_restrack_entry *res) 160 { 161 struct ib_device *dev = res_to_dev(res); 162 163 if (!dev) 164 return; 165 166 if (res->type != RDMA_RESTRACK_CM_ID || !res_is_user(res)) 167 res->task = NULL; 168 169 if (res_is_user(res)) { 170 if (!res->task) 171 rdma_restrack_set_task(res, current); 172 res->kern_name = NULL; 173 } else { 174 set_kern_name(res); 175 } 176 177 kref_init(&res->kref); 178 init_completion(&res->comp); 179 res->valid = true; 180 181 down_write(&dev->res.rwsem); 182 hash_add(dev->res.hash, &res->node, res->type); 183 up_write(&dev->res.rwsem); 184 } 185 EXPORT_SYMBOL(rdma_restrack_add); 186 187 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res) 188 { 189 return kref_get_unless_zero(&res->kref); 190 } 191 EXPORT_SYMBOL(rdma_restrack_get); 192 193 static void restrack_release(struct kref *kref) 194 { 195 struct rdma_restrack_entry *res; 196 197 res = container_of(kref, struct rdma_restrack_entry, kref); 198 complete(&res->comp); 199 } 200 201 int rdma_restrack_put(struct rdma_restrack_entry *res) 202 { 203 return kref_put(&res->kref, restrack_release); 204 } 205 EXPORT_SYMBOL(rdma_restrack_put); 206 207 void rdma_restrack_del(struct rdma_restrack_entry *res) 208 { 209 struct ib_device *dev; 210 211 if (!res->valid) 212 return; 213 214 dev = res_to_dev(res); 215 if (!dev) 216 return; 217 218 rdma_restrack_put(res); 219 220 wait_for_completion(&res->comp); 221 222 down_write(&dev->res.rwsem); 223 hash_del(&res->node); 224 res->valid = false; 225 if (res->task) 226 put_task_struct(res->task); 227 up_write(&dev->res.rwsem); 228 } 229 EXPORT_SYMBOL(rdma_restrack_del); 230