Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

RDMA/restrack: Hide restrack DB from IB/core

There is no need to expose internals of restrack DB to IB/core.

Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>

authored by

Leon Romanovsky and committed by
Jason Gunthorpe
41eda65c 48118527

+115 -67
+5 -1
drivers/infiniband/core/device.c
··· 45 45 #include <rdma/ib_cache.h> 46 46 47 47 #include "core_priv.h" 48 + #include "restrack.h" 48 49 49 50 MODULE_AUTHOR("Roland Dreier"); 50 51 MODULE_DESCRIPTION("core kernel InfiniBand API"); ··· 339 338 if (!device) 340 339 return NULL; 341 340 342 - rdma_restrack_init(device); 341 + if (rdma_restrack_init(device)) { 342 + kfree(device); 343 + return NULL; 344 + } 343 345 344 346 device->dev.class = &ib_class; 345 347 device->groups[0] = &ib_dev_attr_group;
+10 -7
drivers/infiniband/core/nldev.c
··· 39 39 40 40 #include "core_priv.h" 41 41 #include "cma_priv.h" 42 + #include "restrack.h" 42 43 43 44 static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = { 44 45 [RDMA_NLDEV_ATTR_DEV_INDEX] = { .type = NLA_U32 }, ··· 1028 1027 unsigned long id; 1029 1028 u32 index, port = 0; 1030 1029 bool filled = false; 1030 + struct xarray *xa; 1031 1031 1032 1032 err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 1033 1033 nldev_policy, NULL); ··· 1076 1074 1077 1075 has_cap_net_admin = netlink_capable(cb->skb, CAP_NET_ADMIN); 1078 1076 1079 - down_read(&device->res.rwsem); 1077 + xa = &device->res->xa[res_type]; 1078 + down_read(&device->res->rwsem); 1080 1079 /* 1081 1080 * FIXME: if the skip ahead is something common this loop should 1082 1081 * use xas_for_each & xas_pause to optimize, we can have a lot of 1083 1082 * objects. 1084 1083 */ 1085 - xa_for_each(&device->res.xa[res_type], id, res) { 1084 + xa_for_each(xa, id, res) { 1086 1085 if (idx < start) 1087 1086 goto next; 1088 1087 ··· 1104 1101 if (!entry_attr) { 1105 1102 ret = -EMSGSIZE; 1106 1103 rdma_restrack_put(res); 1107 - up_read(&device->res.rwsem); 1104 + up_read(&device->res->rwsem); 1108 1105 break; 1109 1106 } 1110 - up_read(&device->res.rwsem); 1111 1107 1108 + up_read(&device->res->rwsem); 1112 1109 ret = fe->fill_res_func(skb, has_cap_net_admin, res, port); 1113 - down_read(&device->res.rwsem); 1110 + down_read(&device->res->rwsem); 1114 1111 /* 1115 1112 * Return resource back, but it won't be released till 1116 1113 * the &device->res.rwsem will be released for write. ··· 1128 1125 nla_nest_end(skb, entry_attr); 1129 1126 next: idx++; 1130 1127 } 1131 - up_read(&device->res.rwsem); 1128 + up_read(&device->res->rwsem); 1132 1129 1133 1130 nla_nest_end(skb, table_attr); 1134 1131 nlmsg_end(skb, nlh); ··· 1146 1143 1147 1144 res_err: 1148 1145 nla_nest_cancel(skb, table_attr); 1149 - up_read(&device->res.rwsem); 1146 + up_read(&device->res->rwsem); 1150 1147 1151 1148 err: 1152 1149 nlmsg_cancel(skb, nlh);
+58 -27
drivers/infiniband/core/restrack.c
··· 9 9 #include <linux/mutex.h> 10 10 #include <linux/sched/task.h> 11 11 #include <linux/pid_namespace.h> 12 + #include <linux/rwsem.h> 12 13 13 14 #include "cma_priv.h" 15 + #include "restrack.h" 14 16 15 17 static int rt_xa_alloc_cyclic(struct xarray *xa, u32 *id, void *entry, 16 18 u32 *next) ··· 37 35 } 38 36 39 37 /** 40 - * rdma_restrack_init() - initialize resource tracking 38 + * rdma_restrack_init() - initialize and allocate resource tracking 41 39 * @dev: IB device 40 + * 41 + * Return: 0 on success 42 42 */ 43 - void rdma_restrack_init(struct ib_device *dev) 43 + int rdma_restrack_init(struct ib_device *dev) 44 44 { 45 - struct rdma_restrack_root *res = &dev->res; 45 + struct rdma_restrack_root *rt; 46 46 int i; 47 47 48 - for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) 49 - xa_init_flags(&res->xa[i], XA_FLAGS_ALLOC); 48 + dev->res = kzalloc(sizeof(*rt), GFP_KERNEL); 49 + if (!dev->res) 50 + return -ENOMEM; 50 51 51 - init_rwsem(&res->rwsem); 52 + rt = dev->res; 53 + 54 + for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) 55 + xa_init_flags(&rt->xa[i], XA_FLAGS_ALLOC); 56 + init_rwsem(&rt->rwsem); 57 + 58 + return 0; 52 59 } 53 60 54 61 static const char *type2str(enum rdma_restrack_type type) ··· 80 69 */ 81 70 void rdma_restrack_clean(struct ib_device *dev) 82 71 { 83 - struct rdma_restrack_root *res = &dev->res; 72 + struct rdma_restrack_root *rt = dev->res; 84 73 struct rdma_restrack_entry *e; 85 74 char buf[TASK_COMM_LEN]; 86 75 bool found = false; ··· 88 77 int i; 89 78 90 79 for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) { 91 - if (!xa_empty(&res->xa[i])) { 80 + struct xarray *xa = &dev->res->xa[i]; 81 + 82 + if (!xa_empty(xa)) { 92 83 unsigned long index; 93 84 94 85 if (!found) { 95 86 pr_err("restrack: %s", CUT_HERE); 96 87 dev_err(&dev->dev, "BUG: RESTRACK detected leak of resources\n"); 97 88 } 98 - xa_for_each(&res->xa[i], index, e) { 89 + xa_for_each(xa, index, e) { 99 90 if (rdma_is_kernel_res(e)) { 100 91 owner = e->kern_name; 101 92 } else { ··· 117 104 } 118 105 found = true; 119 106 } 120 - xa_destroy(&res->xa[i]); 107 + xa_destroy(xa); 121 108 } 122 109 if (found) 123 110 pr_err("restrack: %s", CUT_HERE); 111 + 112 + kfree(rt); 124 113 } 125 114 126 115 /** ··· 134 119 int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type, 135 120 struct pid_namespace *ns) 136 121 { 137 - struct rdma_restrack_root *res = &dev->res; 122 + struct xarray *xa = &dev->res->xa[type]; 138 123 struct rdma_restrack_entry *e; 139 124 unsigned long index = 0; 140 125 u32 cnt = 0; 141 126 142 - down_read(&res->rwsem); 143 - xa_for_each(&res->xa[type], index, e) { 127 + down_read(&dev->res->rwsem); 128 + xa_for_each(xa, index, e) { 144 129 if (ns == &init_pid_ns || 145 130 (!rdma_is_kernel_res(e) && 146 131 ns == task_active_pid_ns(e->task))) 147 132 cnt++; 148 133 } 149 - up_read(&res->rwsem); 134 + up_read(&dev->res->rwsem); 150 135 return cnt; 151 136 } 152 137 EXPORT_SYMBOL(rdma_restrack_count); ··· 217 202 static void rdma_restrack_add(struct rdma_restrack_entry *res) 218 203 { 219 204 struct ib_device *dev = res_to_dev(res); 205 + struct rdma_restrack_root *rt; 206 + struct xarray *xa; 220 207 int ret; 221 208 222 209 if (!dev) 223 210 return; 224 211 212 + rt = dev->res; 213 + xa = &dev->res->xa[res->type]; 214 + 225 215 kref_init(&res->kref); 226 216 init_completion(&res->comp); 227 - 228 - ret = rt_xa_alloc_cyclic(&dev->res.xa[res->type], &res->id, res, 229 - &dev->res.next_id[res->type]); 230 - 217 + ret = rt_xa_alloc_cyclic(xa, &res->id, res, &rt->next_id[res->type]); 231 218 if (!ret) 232 219 res->valid = true; 233 220 } ··· 283 266 rdma_restrack_get_byid(struct ib_device *dev, 284 267 enum rdma_restrack_type type, u32 id) 285 268 { 286 - struct rdma_restrack_root *rt = &dev->res; 269 + struct xarray *xa = &dev->res->xa[type]; 287 270 struct rdma_restrack_entry *res; 288 271 289 - down_read(&dev->res.rwsem); 290 - res = xa_load(&rt->xa[type], id); 272 + down_read(&dev->res->rwsem); 273 + res = xa_load(xa, id); 291 274 if (!res || !rdma_restrack_get(res)) 292 275 res = ERR_PTR(-ENOENT); 293 - up_read(&dev->res.rwsem); 276 + up_read(&dev->res->rwsem); 294 277 295 278 return res; 296 279 } ··· 312 295 313 296 void rdma_restrack_del(struct rdma_restrack_entry *res) 314 297 { 315 - struct ib_device *dev; 298 + struct ib_device *dev = res_to_dev(res); 299 + struct xarray *xa; 316 300 317 301 if (!res->valid) 318 302 goto out; 319 303 320 - dev = res_to_dev(res); 304 + /* 305 + * All objects except CM_ID set valid device immediately 306 + * after new object is created, it means that for not valid 307 + * objects will still have "dev". 308 + * 309 + * It is not the case for CM_ID, newly created object has 310 + * this field set to NULL and it is set in _cma_attach_to_dev() 311 + * only. 312 + * 313 + * Because we don't want to add any conditions on call 314 + * to rdma_restrack_del(), the check below protects from 315 + * NULL-dereference. 316 + */ 321 317 if (!dev) 322 318 return; 323 319 324 - down_write(&dev->res.rwsem); 325 - xa_erase(&dev->res.xa[res->type], res->id); 320 + xa = &dev->res->xa[res->type]; 321 + down_write(&dev->res->rwsem); 322 + xa_erase(xa, res->id); 326 323 res->valid = false; 327 - up_write(&dev->res.rwsem); 324 + up_write(&dev->res->rwsem); 328 325 329 326 rdma_restrack_put(res); 330 327 wait_for_completion(&res->comp);
+39
drivers/infiniband/core/restrack.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* 3 + * Copyright (c) 2017-2019 Mellanox Technologies. All rights reserved. 4 + */ 5 + 6 + #ifndef _RDMA_CORE_RESTRACK_H_ 7 + #define _RDMA_CORE_RESTRACK_H_ 8 + 9 + #include <linux/mutex.h> 10 + #include <linux/rwsem.h> 11 + 12 + /** 13 + * struct rdma_restrack_root - main resource tracking management 14 + * entity, per-device 15 + */ 16 + struct rdma_restrack_root { 17 + /* 18 + * @rwsem: Read/write lock to protect erase of entry. 19 + * Lists and insertions are protected by XArray internal lock. 20 + */ 21 + struct rw_semaphore rwsem; 22 + /** 23 + * @xa: Array of XArray structures to hold restrack entries. 24 + * We want to use array of XArrays because insertion is type 25 + * dependent. For types with xisiting unique ID (like QPN), 26 + * we will insert to that unique index. For other types, 27 + * we insert based on pointers and auto-allocate unique index. 28 + */ 29 + struct xarray xa[RDMA_RESTRACK_MAX]; 30 + /** 31 + * @next_id: Next ID to support cyclic allocation 32 + */ 33 + u32 next_id[RDMA_RESTRACK_MAX]; 34 + }; 35 + 36 + 37 + int rdma_restrack_init(struct ib_device *dev); 38 + void rdma_restrack_clean(struct ib_device *dev); 39 + #endif /* _RDMA_CORE_RESTRACK_H_ */
+3 -4
include/rdma/ib_verbs.h
··· 2533 2533 DECLARE_RDMA_OBJ_SIZE(ib_pd); 2534 2534 }; 2535 2535 2536 + struct rdma_restrack_root; 2537 + 2536 2538 struct ib_device { 2537 2539 /* Do not access @dma_device directly from ULP nor from HW drivers. */ 2538 2540 struct device *dma_device; ··· 2591 2589 #endif 2592 2590 2593 2591 u32 index; 2594 - /* 2595 - * Implementation details of the RDMA core, don't use in drivers 2596 - */ 2597 - struct rdma_restrack_root res; 2592 + struct rdma_restrack_root *res; 2598 2593 2599 2594 const struct uapi_definition *driver_def; 2600 2595 enum rdma_driver_id driver_id;
-28
include/rdma/restrack.h
··· 7 7 #define _RDMA_RESTRACK_H_ 8 8 9 9 #include <linux/typecheck.h> 10 - #include <linux/rwsem.h> 11 10 #include <linux/sched.h> 12 11 #include <linux/kref.h> 13 12 #include <linux/completion.h> ··· 49 50 }; 50 51 51 52 struct ib_device; 52 - struct rdma_restrack_entry; 53 - 54 - /** 55 - * struct rdma_restrack_root - main resource tracking management 56 - * entity, per-device 57 - */ 58 - struct rdma_restrack_root { 59 - /* 60 - * @rwsem: Read/write lock to protect erase of entry. 61 - * Lists and insertions are protected by XArray internal lock. 62 - */ 63 - struct rw_semaphore rwsem; 64 - /** 65 - * @xa: Array of XArray structures to hold restrack entries. 66 - * We want to use array of XArrays because insertion is type 67 - * dependent. For types with xisiting unique ID (like QPN), 68 - * we will insert to that unique index. For other types, 69 - * we insert based on pointers and auto-allocate unique index. 70 - */ 71 - struct xarray xa[RDMA_RESTRACK_MAX]; 72 - /** 73 - * @next_id: Next ID to support cyclic allocation 74 - */ 75 - u32 next_id[RDMA_RESTRACK_MAX]; 76 - }; 77 53 78 54 /** 79 55 * struct rdma_restrack_entry - metadata per-entry ··· 99 125 u32 id; 100 126 }; 101 127 102 - void rdma_restrack_init(struct ib_device *dev); 103 - void rdma_restrack_clean(struct ib_device *dev); 104 128 int rdma_restrack_count(struct ib_device *dev, 105 129 enum rdma_restrack_type type, 106 130 struct pid_namespace *ns);