1 /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ 2 /* 3 * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved. 4 */ 5 6 #include <rdma/ib_verbs.h> 7 #include <rdma/restrack.h> 8 #include <linux/mutex.h> 9 #include <linux/sched/task.h> 10 #include <linux/pid_namespace.h> 11 12 void rdma_restrack_init(struct rdma_restrack_root *res) 13 { 14 init_rwsem(&res->rwsem); 15 } 16 17 void rdma_restrack_clean(struct rdma_restrack_root *res) 18 { 19 WARN_ON_ONCE(!hash_empty(res->hash)); 20 } 21 22 int rdma_restrack_count(struct rdma_restrack_root *res, 23 enum rdma_restrack_type type, 24 struct pid_namespace *ns) 25 { 26 struct rdma_restrack_entry *e; 27 u32 cnt = 0; 28 29 down_read(&res->rwsem); 30 hash_for_each_possible(res->hash, e, node, type) { 31 if (ns == &init_pid_ns || 32 (!rdma_is_kernel_res(e) && 33 ns == task_active_pid_ns(e->task))) 34 cnt++; 35 } 36 up_read(&res->rwsem); 37 return cnt; 38 } 39 EXPORT_SYMBOL(rdma_restrack_count); 40 41 static void set_kern_name(struct rdma_restrack_entry *res) 42 { 43 enum rdma_restrack_type type = res->type; 44 struct ib_qp *qp; 45 46 if (type != RDMA_RESTRACK_QP) 47 /* PD and CQ types already have this name embedded in */ 48 return; 49 50 qp = container_of(res, struct ib_qp, res); 51 if (!qp->pd) { 52 WARN_ONCE(true, "XRC QPs are not supported\n"); 53 /* Survive, despite the programmer's error */ 54 res->kern_name = " "; 55 return; 56 } 57 58 res->kern_name = qp->pd->res.kern_name; 59 } 60 61 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res) 62 { 63 enum rdma_restrack_type type = res->type; 64 struct ib_device *dev; 65 struct ib_pd *pd; 66 struct ib_cq *cq; 67 struct ib_qp *qp; 68 69 switch (type) { 70 case RDMA_RESTRACK_PD: 71 pd = container_of(res, struct ib_pd, res); 72 dev = pd->device; 73 break; 74 case RDMA_RESTRACK_CQ: 75 cq = container_of(res, struct ib_cq, res); 76 dev = cq->device; 77 break; 78 case RDMA_RESTRACK_QP: 79 qp = container_of(res, struct ib_qp, res); 80 dev = qp->device; 81 break; 82 default: 83 WARN_ONCE(true, "Wrong resource tracking type %u\n", type); 84 return NULL; 85 } 86 87 return dev; 88 } 89 90 static bool res_is_user(struct rdma_restrack_entry *res) 91 { 92 switch (res->type) { 93 case RDMA_RESTRACK_PD: 94 return container_of(res, struct ib_pd, res)->uobject; 95 case RDMA_RESTRACK_CQ: 96 return container_of(res, struct ib_cq, res)->uobject; 97 case RDMA_RESTRACK_QP: 98 return container_of(res, struct ib_qp, res)->uobject; 99 default: 100 WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type); 101 return false; 102 } 103 } 104 105 void rdma_restrack_add(struct rdma_restrack_entry *res) 106 { 107 struct ib_device *dev = res_to_dev(res); 108 109 if (!dev) 110 return; 111 112 if (res_is_user(res)) { 113 get_task_struct(current); 114 res->task = current; 115 res->kern_name = NULL; 116 } else { 117 set_kern_name(res); 118 res->task = NULL; 119 } 120 121 kref_init(&res->kref); 122 init_completion(&res->comp); 123 res->valid = true; 124 125 down_write(&dev->res.rwsem); 126 hash_add(dev->res.hash, &res->node, res->type); 127 up_write(&dev->res.rwsem); 128 } 129 EXPORT_SYMBOL(rdma_restrack_add); 130 131 int __must_check rdma_restrack_get(struct rdma_restrack_entry *res) 132 { 133 return kref_get_unless_zero(&res->kref); 134 } 135 EXPORT_SYMBOL(rdma_restrack_get); 136 137 static void restrack_release(struct kref *kref) 138 { 139 struct rdma_restrack_entry *res; 140 141 res = container_of(kref, struct rdma_restrack_entry, kref); 142 complete(&res->comp); 143 } 144 145 int rdma_restrack_put(struct rdma_restrack_entry *res) 146 { 147 return kref_put(&res->kref, restrack_release); 148 } 149 EXPORT_SYMBOL(rdma_restrack_put); 150 151 void rdma_restrack_del(struct rdma_restrack_entry *res) 152 { 153 struct ib_device *dev; 154 155 if (!res->valid) 156 return; 157 158 dev = res_to_dev(res); 159 if (!dev) 160 return; 161 162 rdma_restrack_put(res); 163 164 wait_for_completion(&res->comp); 165 166 down_write(&dev->res.rwsem); 167 hash_del(&res->node); 168 res->valid = false; 169 if (res->task) 170 put_task_struct(res->task); 171 up_write(&dev->res.rwsem); 172 } 173 EXPORT_SYMBOL(rdma_restrack_del); 174