restrack.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2. /*
  3. * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
  4. */
  5. #include <rdma/rdma_cm.h>
  6. #include <rdma/ib_verbs.h>
  7. #include <rdma/restrack.h>
  8. #include <rdma/rdma_counter.h>
  9. #include <linux/mutex.h>
  10. #include <linux/sched/task.h>
  11. #include <linux/pid_namespace.h>
  12. #include "cma_priv.h"
  13. #include "restrack.h"
  14. /**
  15. * rdma_restrack_init() - initialize and allocate resource tracking
  16. * @dev: IB device
  17. *
  18. * Return: 0 on success
  19. */
  20. int rdma_restrack_init(struct ib_device *dev)
  21. {
  22. struct rdma_restrack_root *rt;
  23. int i;
  24. dev->res = kcalloc(RDMA_RESTRACK_MAX, sizeof(*rt), GFP_KERNEL);
  25. if (!dev->res)
  26. return -ENOMEM;
  27. rt = dev->res;
  28. for (i = 0; i < RDMA_RESTRACK_MAX; i++)
  29. xa_init_flags(&rt[i].xa, XA_FLAGS_ALLOC);
  30. return 0;
  31. }
  32. /**
  33. * rdma_restrack_clean() - clean resource tracking
  34. * @dev: IB device
  35. */
  36. void rdma_restrack_clean(struct ib_device *dev)
  37. {
  38. struct rdma_restrack_root *rt = dev->res;
  39. int i;
  40. for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
  41. struct xarray *xa = &dev->res[i].xa;
  42. WARN_ON(!xa_empty(xa));
  43. xa_destroy(xa);
  44. }
  45. kfree(rt);
  46. }
  47. /**
  48. * rdma_restrack_count() - the current usage of specific object
  49. * @dev: IB device
  50. * @type: actual type of object to operate
  51. * @show_details: count driver specific objects
  52. */
  53. int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
  54. bool show_details)
  55. {
  56. struct rdma_restrack_root *rt = &dev->res[type];
  57. struct rdma_restrack_entry *e;
  58. XA_STATE(xas, &rt->xa, 0);
  59. u32 cnt = 0;
  60. xa_lock(&rt->xa);
  61. xas_for_each(&xas, e, U32_MAX) {
  62. if (xa_get_mark(&rt->xa, e->id, RESTRACK_DD) && !show_details)
  63. continue;
  64. cnt++;
  65. }
  66. xa_unlock(&rt->xa);
  67. return cnt;
  68. }
  69. EXPORT_SYMBOL(rdma_restrack_count);
  70. static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
  71. {
  72. switch (res->type) {
  73. case RDMA_RESTRACK_PD:
  74. return container_of(res, struct ib_pd, res)->device;
  75. case RDMA_RESTRACK_CQ:
  76. return container_of(res, struct ib_cq, res)->device;
  77. case RDMA_RESTRACK_QP:
  78. return container_of(res, struct ib_qp, res)->device;
  79. case RDMA_RESTRACK_CM_ID:
  80. return container_of(res, struct rdma_id_private,
  81. res)->id.device;
  82. case RDMA_RESTRACK_MR:
  83. return container_of(res, struct ib_mr, res)->device;
  84. case RDMA_RESTRACK_CTX:
  85. return container_of(res, struct ib_ucontext, res)->device;
  86. case RDMA_RESTRACK_COUNTER:
  87. return container_of(res, struct rdma_counter, res)->device;
  88. case RDMA_RESTRACK_SRQ:
  89. return container_of(res, struct ib_srq, res)->device;
  90. default:
  91. WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
  92. return NULL;
  93. }
  94. }
  95. /**
  96. * rdma_restrack_attach_task() - attach the task onto this resource,
  97. * valid for user space restrack entries.
  98. * @res: resource entry
  99. * @task: the task to attach
  100. */
  101. static void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
  102. struct task_struct *task)
  103. {
  104. if (WARN_ON_ONCE(!task))
  105. return;
  106. if (res->task)
  107. put_task_struct(res->task);
  108. get_task_struct(task);
  109. res->task = task;
  110. res->user = true;
  111. }
  112. /**
  113. * rdma_restrack_set_name() - set the task for this resource
  114. * @res: resource entry
  115. * @caller: kernel name, the current task will be used if the caller is NULL.
  116. */
  117. void rdma_restrack_set_name(struct rdma_restrack_entry *res, const char *caller)
  118. {
  119. if (caller) {
  120. res->kern_name = caller;
  121. return;
  122. }
  123. rdma_restrack_attach_task(res, current);
  124. }
  125. EXPORT_SYMBOL(rdma_restrack_set_name);
  126. /**
  127. * rdma_restrack_parent_name() - set the restrack name properties based
  128. * on parent restrack
  129. * @dst: destination resource entry
  130. * @parent: parent resource entry
  131. */
  132. void rdma_restrack_parent_name(struct rdma_restrack_entry *dst,
  133. const struct rdma_restrack_entry *parent)
  134. {
  135. if (rdma_is_kernel_res(parent))
  136. dst->kern_name = parent->kern_name;
  137. else
  138. rdma_restrack_attach_task(dst, parent->task);
  139. }
  140. EXPORT_SYMBOL(rdma_restrack_parent_name);
  141. /**
  142. * rdma_restrack_new() - Initializes new restrack entry to allow _put() interface
  143. * to release memory in fully automatic way.
  144. * @res: Entry to initialize
  145. * @type: REstrack type
  146. */
  147. void rdma_restrack_new(struct rdma_restrack_entry *res,
  148. enum rdma_restrack_type type)
  149. {
  150. kref_init(&res->kref);
  151. init_completion(&res->comp);
  152. res->type = type;
  153. }
  154. EXPORT_SYMBOL(rdma_restrack_new);
  155. /**
  156. * rdma_restrack_add() - add object to the reource tracking database
  157. * @res: resource entry
  158. */
  159. void rdma_restrack_add(struct rdma_restrack_entry *res)
  160. {
  161. struct ib_device *dev = res_to_dev(res);
  162. struct rdma_restrack_root *rt;
  163. int ret = 0;
  164. if (!dev)
  165. return;
  166. if (res->no_track)
  167. goto out;
  168. rt = &dev->res[res->type];
  169. if (res->type == RDMA_RESTRACK_QP) {
  170. /* Special case to ensure that LQPN points to right QP */
  171. struct ib_qp *qp = container_of(res, struct ib_qp, res);
  172. WARN_ONCE(qp->qp_num >> 24 || qp->port >> 8,
  173. "QP number 0x%0X and port 0x%0X", qp->qp_num,
  174. qp->port);
  175. res->id = qp->qp_num;
  176. if (qp->qp_type == IB_QPT_SMI || qp->qp_type == IB_QPT_GSI)
  177. res->id |= qp->port << 24;
  178. ret = xa_insert(&rt->xa, res->id, res, GFP_KERNEL);
  179. if (ret)
  180. res->id = 0;
  181. if (qp->qp_type >= IB_QPT_DRIVER)
  182. xa_set_mark(&rt->xa, res->id, RESTRACK_DD);
  183. } else if (res->type == RDMA_RESTRACK_COUNTER) {
  184. /* Special case to ensure that cntn points to right counter */
  185. struct rdma_counter *counter;
  186. counter = container_of(res, struct rdma_counter, res);
  187. ret = xa_insert(&rt->xa, counter->id, res, GFP_KERNEL);
  188. res->id = ret ? 0 : counter->id;
  189. } else {
  190. ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
  191. &rt->next_id, GFP_KERNEL);
  192. ret = (ret < 0) ? ret : 0;
  193. }
  194. out:
  195. if (!ret)
  196. res->valid = true;
  197. }
  198. EXPORT_SYMBOL(rdma_restrack_add);
  199. int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
  200. {
  201. return kref_get_unless_zero(&res->kref);
  202. }
  203. EXPORT_SYMBOL(rdma_restrack_get);
  204. /**
  205. * rdma_restrack_get_byid() - translate from ID to restrack object
  206. * @dev: IB device
  207. * @type: resource track type
  208. * @id: ID to take a look
  209. *
  210. * Return: Pointer to restrack entry or -ENOENT in case of error.
  211. */
  212. struct rdma_restrack_entry *
  213. rdma_restrack_get_byid(struct ib_device *dev,
  214. enum rdma_restrack_type type, u32 id)
  215. {
  216. struct rdma_restrack_root *rt = &dev->res[type];
  217. struct rdma_restrack_entry *res;
  218. xa_lock(&rt->xa);
  219. res = xa_load(&rt->xa, id);
  220. if (!res || !rdma_restrack_get(res))
  221. res = ERR_PTR(-ENOENT);
  222. xa_unlock(&rt->xa);
  223. return res;
  224. }
  225. EXPORT_SYMBOL(rdma_restrack_get_byid);
  226. static void restrack_release(struct kref *kref)
  227. {
  228. struct rdma_restrack_entry *res;
  229. res = container_of(kref, struct rdma_restrack_entry, kref);
  230. if (res->task) {
  231. put_task_struct(res->task);
  232. res->task = NULL;
  233. }
  234. complete(&res->comp);
  235. }
  236. int rdma_restrack_put(struct rdma_restrack_entry *res)
  237. {
  238. return kref_put(&res->kref, restrack_release);
  239. }
  240. EXPORT_SYMBOL(rdma_restrack_put);
  241. /**
  242. * rdma_restrack_del() - delete object from the reource tracking database
  243. * @res: resource entry
  244. */
  245. void rdma_restrack_del(struct rdma_restrack_entry *res)
  246. {
  247. struct rdma_restrack_entry *old;
  248. struct rdma_restrack_root *rt;
  249. struct ib_device *dev;
  250. if (!res->valid) {
  251. if (res->task) {
  252. put_task_struct(res->task);
  253. res->task = NULL;
  254. }
  255. return;
  256. }
  257. if (res->no_track)
  258. goto out;
  259. dev = res_to_dev(res);
  260. if (WARN_ON(!dev))
  261. return;
  262. rt = &dev->res[res->type];
  263. old = xa_erase(&rt->xa, res->id);
  264. WARN_ON(old != res);
  265. out:
  266. res->valid = false;
  267. rdma_restrack_put(res);
  268. wait_for_completion(&res->comp);
  269. }
  270. EXPORT_SYMBOL(rdma_restrack_del);