]>
Commit | Line | Data |
---|---|---|
38321256 MB |
1 | /* |
2 | * Copyright (c) 2016, Mellanox Technologies inc. All rights reserved. | |
3 | * | |
4 | * This software is available to you under a choice of one of two | |
5 | * licenses. You may choose to be licensed under the terms of the GNU | |
6 | * General Public License (GPL) Version 2, available from the file | |
7 | * COPYING in the main directory of this source tree, or the | |
8 | * OpenIB.org BSD license below: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or | |
11 | * without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistributions of source code must retain the above | |
15 | * copyright notice, this list of conditions and the following | |
16 | * disclaimer. | |
17 | * | |
18 | * - Redistributions in binary form must reproduce the above | |
19 | * copyright notice, this list of conditions and the following | |
20 | * disclaimer in the documentation and/or other materials | |
21 | * provided with the distribution. | |
22 | * | |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
30 | * SOFTWARE. | |
31 | */ | |
32 | ||
33 | #include <linux/file.h> | |
34 | #include <linux/anon_inodes.h> | |
e951747a | 35 | #include <linux/sched/mm.h> |
38321256 MB |
36 | #include <rdma/ib_verbs.h> |
37 | #include <rdma/uverbs_types.h> | |
38 | #include <linux/rcupdate.h> | |
a0aa309c | 39 | #include <rdma/uverbs_ioctl.h> |
fac9658c | 40 | #include <rdma/rdma_user_ioctl.h> |
38321256 MB |
41 | #include "uverbs.h" |
42 | #include "core_priv.h" | |
43 | #include "rdma_core.h" | |
44 | ||
30004b86 | 45 | static void uverbs_uobject_free(struct kref *ref) |
38321256 | 46 | { |
8bdf9dd9 | 47 | kfree_rcu(container_of(ref, struct ib_uobject, ref), rcu); |
38321256 MB |
48 | } |
49 | ||
6898d1c6 JG |
50 | /* |
51 | * In order to indicate we no longer needs this uobject, uverbs_uobject_put | |
52 | * is called. When the reference count is decreased, the uobject is freed. | |
53 | * For example, this is used when attaching a completion channel to a CQ. | |
54 | */ | |
38321256 MB |
55 | void uverbs_uobject_put(struct ib_uobject *uobject) |
56 | { | |
30004b86 | 57 | kref_put(&uobject->ref, uverbs_uobject_free); |
38321256 | 58 | } |
6898d1c6 | 59 | EXPORT_SYMBOL(uverbs_uobject_put); |
38321256 | 60 | |
9867f5c6 JG |
61 | static int uverbs_try_lock_object(struct ib_uobject *uobj, |
62 | enum rdma_lookup_mode mode) | |
38321256 MB |
63 | { |
64 | /* | |
30004b86 MB |
65 | * When a shared access is required, we use a positive counter. Each |
66 | * shared access request checks that the value != -1 and increment it. | |
67 | * Exclusive access is required for operations like write or destroy. | |
68 | * In exclusive access mode, we check that the counter is zero (nobody | |
69 | * claimed this object) and we set it to -1. Releasing a shared access | |
70 | * lock is done simply by decreasing the counter. As for exclusive | |
71 | * access locks, since only a single one of them is is allowed | |
72 | * concurrently, setting the counter to zero is enough for releasing | |
73 | * this lock. | |
38321256 | 74 | */ |
9867f5c6 JG |
75 | switch (mode) { |
76 | case UVERBS_LOOKUP_READ: | |
bfc18e38 | 77 | return atomic_fetch_add_unless(&uobj->usecnt, 1, -1) == -1 ? |
38321256 | 78 | -EBUSY : 0; |
9867f5c6 | 79 | case UVERBS_LOOKUP_WRITE: |
7452a3c7 | 80 | /* lock is exclusive */ |
9867f5c6 | 81 | return atomic_cmpxchg(&uobj->usecnt, 0, -1) == 0 ? 0 : -EBUSY; |
7452a3c7 JG |
82 | case UVERBS_LOOKUP_DESTROY: |
83 | return 0; | |
9867f5c6 JG |
84 | } |
85 | return 0; | |
38321256 MB |
86 | } |
87 | ||
9867f5c6 JG |
88 | static void assert_uverbs_usecnt(struct ib_uobject *uobj, |
89 | enum rdma_lookup_mode mode) | |
87ad80ab JG |
90 | { |
91 | #ifdef CONFIG_LOCKDEP | |
9867f5c6 JG |
92 | switch (mode) { |
93 | case UVERBS_LOOKUP_READ: | |
87ad80ab | 94 | WARN_ON(atomic_read(&uobj->usecnt) <= 0); |
9867f5c6 JG |
95 | break; |
96 | case UVERBS_LOOKUP_WRITE: | |
97 | WARN_ON(atomic_read(&uobj->usecnt) != -1); | |
98 | break; | |
7452a3c7 JG |
99 | case UVERBS_LOOKUP_DESTROY: |
100 | break; | |
9867f5c6 | 101 | } |
87ad80ab JG |
102 | #endif |
103 | } | |
104 | ||
105 | /* | |
1e857e65 JG |
106 | * This must be called with the hw_destroy_rwsem locked for read or write, |
107 | * also the uobject itself must be locked for write. | |
87ad80ab JG |
108 | * |
109 | * Upon return the HW object is guaranteed to be destroyed. | |
110 | * | |
111 | * For RDMA_REMOVE_ABORT, the hw_destroy_rwsem is not required to be held, | |
112 | * however the type's allocat_commit function cannot have been called and the | |
113 | * uobject cannot be on the uobjects_lists | |
114 | * | |
115 | * For RDMA_REMOVE_DESTROY the caller shold be holding a kref (eg via | |
116 | * rdma_lookup_get_uobject) and the object is left in a state where the caller | |
117 | * needs to call rdma_lookup_put_uobject. | |
118 | * | |
119 | * For all other destroy modes this function internally unlocks the uobject | |
120 | * and consumes the kref on the uobj. | |
121 | */ | |
122 | static int uverbs_destroy_uobject(struct ib_uobject *uobj, | |
a6a3797d SR |
123 | enum rdma_remove_reason reason, |
124 | struct uverbs_attr_bundle *attrs) | |
87ad80ab | 125 | { |
feec576a | 126 | struct ib_uverbs_file *ufile = attrs->ufile; |
87ad80ab JG |
127 | unsigned long flags; |
128 | int ret; | |
129 | ||
1e857e65 | 130 | lockdep_assert_held(&ufile->hw_destroy_rwsem); |
9867f5c6 | 131 | assert_uverbs_usecnt(uobj, UVERBS_LOOKUP_WRITE); |
87ad80ab | 132 | |
849e1490 JG |
133 | if (reason == RDMA_REMOVE_ABORT) { |
134 | WARN_ON(!list_empty(&uobj->list)); | |
135 | WARN_ON(!uobj->context); | |
136 | uobj->uapi_object->type_class->alloc_abort(uobj); | |
137 | } else if (uobj->object) { | |
a6a3797d SR |
138 | ret = uobj->uapi_object->type_class->destroy_hw(uobj, reason, |
139 | attrs); | |
87ad80ab JG |
140 | if (ret) { |
141 | if (ib_is_destroy_retryable(ret, reason, uobj)) | |
142 | return ret; | |
143 | ||
144 | /* Nothing to be done, dangle the memory and move on */ | |
145 | WARN(true, | |
146 | "ib_uverbs: failed to remove uobject id %d, driver err=%d", | |
147 | uobj->id, ret); | |
148 | } | |
149 | ||
150 | uobj->object = NULL; | |
151 | } | |
152 | ||
87ad80ab JG |
153 | uobj->context = NULL; |
154 | ||
155 | /* | |
c85f4abe JG |
156 | * For DESTROY the usecnt is not changed, the caller is expected to |
157 | * manage it via uobj_put_destroy(). Only DESTROY can remove the IDR | |
158 | * handle. | |
87ad80ab JG |
159 | */ |
160 | if (reason != RDMA_REMOVE_DESTROY) | |
161 | atomic_set(&uobj->usecnt, 0); | |
0f50d88a | 162 | else |
6b0d08f4 | 163 | uobj->uapi_object->type_class->remove_handle(uobj); |
87ad80ab JG |
164 | |
165 | if (!list_empty(&uobj->list)) { | |
166 | spin_lock_irqsave(&ufile->uobjects_lock, flags); | |
167 | list_del_init(&uobj->list); | |
168 | spin_unlock_irqrestore(&ufile->uobjects_lock, flags); | |
169 | ||
170 | /* | |
171 | * Pairs with the get in rdma_alloc_commit_uobject(), could | |
172 | * destroy uobj. | |
173 | */ | |
174 | uverbs_uobject_put(uobj); | |
175 | } | |
176 | ||
177 | /* | |
178 | * When aborting the stack kref remains owned by the core code, and is | |
179 | * not transferred into the type. Pairs with the get in alloc_uobj | |
180 | */ | |
181 | if (reason == RDMA_REMOVE_ABORT) | |
182 | uverbs_uobject_put(uobj); | |
183 | ||
184 | return 0; | |
185 | } | |
186 | ||
7452a3c7 JG |
187 | /* |
188 | * This calls uverbs_destroy_uobject() using the RDMA_REMOVE_DESTROY | |
189 | * sequence. It should only be used from command callbacks. On success the | |
c85f4abe | 190 | * caller must pair this with uobj_put_destroy(). This |
7452a3c7 JG |
191 | * version requires the caller to have already obtained an |
192 | * LOOKUP_DESTROY uobject kref. | |
193 | */ | |
a6a3797d | 194 | int uobj_destroy(struct ib_uobject *uobj, struct uverbs_attr_bundle *attrs) |
7452a3c7 | 195 | { |
feec576a | 196 | struct ib_uverbs_file *ufile = attrs->ufile; |
7452a3c7 JG |
197 | int ret; |
198 | ||
199 | down_read(&ufile->hw_destroy_rwsem); | |
200 | ||
c85f4abe JG |
201 | /* |
202 | * Once the uobject is destroyed by RDMA_REMOVE_DESTROY then it is left | |
203 | * write locked as the callers put it back with UVERBS_LOOKUP_DESTROY. | |
204 | * This is because any other concurrent thread can still see the object | |
205 | * in the xarray due to RCU. Leaving it locked ensures nothing else will | |
206 | * touch it. | |
207 | */ | |
7452a3c7 JG |
208 | ret = uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE); |
209 | if (ret) | |
210 | goto out_unlock; | |
211 | ||
a6a3797d | 212 | ret = uverbs_destroy_uobject(uobj, RDMA_REMOVE_DESTROY, attrs); |
7452a3c7 JG |
213 | if (ret) { |
214 | atomic_set(&uobj->usecnt, 0); | |
215 | goto out_unlock; | |
216 | } | |
217 | ||
218 | out_unlock: | |
219 | up_read(&ufile->hw_destroy_rwsem); | |
220 | return ret; | |
221 | } | |
222 | ||
c33e73af | 223 | /* |
32ed5c00 JG |
224 | * uobj_get_destroy destroys the HW object and returns a handle to the uobj |
225 | * with a NULL object pointer. The caller must pair this with | |
c85f4abe | 226 | * uobj_put_destroy(). |
c33e73af | 227 | */ |
6b0d08f4 | 228 | struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj, |
70f06b26 | 229 | u32 id, struct uverbs_attr_bundle *attrs) |
c33e73af JG |
230 | { |
231 | struct ib_uobject *uobj; | |
232 | int ret; | |
233 | ||
8313c10f | 234 | uobj = rdma_lookup_get_uobject(obj, attrs->ufile, id, |
70f06b26 | 235 | UVERBS_LOOKUP_DESTROY, attrs); |
c33e73af | 236 | if (IS_ERR(uobj)) |
32ed5c00 | 237 | return uobj; |
c33e73af | 238 | |
a6a3797d | 239 | ret = uobj_destroy(uobj, attrs); |
32ed5c00 | 240 | if (ret) { |
7452a3c7 | 241 | rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_DESTROY); |
32ed5c00 JG |
242 | return ERR_PTR(ret); |
243 | } | |
c33e73af | 244 | |
32ed5c00 JG |
245 | return uobj; |
246 | } | |
247 | ||
248 | /* | |
7106a976 JG |
249 | * Does both uobj_get_destroy() and uobj_put_destroy(). Returns 0 on success |
250 | * (negative errno on failure). For use by callers that do not need the uobj. | |
32ed5c00 | 251 | */ |
6b0d08f4 | 252 | int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id, |
70f06b26 | 253 | struct uverbs_attr_bundle *attrs) |
32ed5c00 JG |
254 | { |
255 | struct ib_uobject *uobj; | |
256 | ||
8313c10f | 257 | uobj = __uobj_get_destroy(obj, id, attrs); |
32ed5c00 JG |
258 | if (IS_ERR(uobj)) |
259 | return PTR_ERR(uobj); | |
c85f4abe | 260 | uobj_put_destroy(uobj); |
7106a976 | 261 | return 0; |
c33e73af JG |
262 | } |
263 | ||
87ad80ab | 264 | /* alloc_uobj must be undone by uverbs_destroy_uobject() */ |
39e83af8 | 265 | static struct ib_uobject *alloc_uobj(struct uverbs_attr_bundle *attrs, |
6b0d08f4 | 266 | const struct uverbs_api_object *obj) |
38321256 | 267 | { |
39e83af8 | 268 | struct ib_uverbs_file *ufile = attrs->ufile; |
22fa27fb | 269 | struct ib_uobject *uobj; |
22fa27fb | 270 | |
39e83af8 JG |
271 | if (!attrs->context) { |
272 | struct ib_ucontext *ucontext = | |
273 | ib_uverbs_get_ucontext_file(ufile); | |
274 | ||
275 | if (IS_ERR(ucontext)) | |
276 | return ERR_CAST(ucontext); | |
277 | attrs->context = ucontext; | |
278 | } | |
38321256 | 279 | |
6b0d08f4 | 280 | uobj = kzalloc(obj->type_attrs->obj_size, GFP_KERNEL); |
38321256 MB |
281 | if (!uobj) |
282 | return ERR_PTR(-ENOMEM); | |
283 | /* | |
284 | * user_handle should be filled by the handler, | |
285 | * The object is added to the list in the commit stage. | |
286 | */ | |
6ef1c828 | 287 | uobj->ufile = ufile; |
39e83af8 | 288 | uobj->context = attrs->context; |
5671f79b | 289 | INIT_LIST_HEAD(&uobj->list); |
6b0d08f4 | 290 | uobj->uapi_object = obj; |
d9dc7a35 JG |
291 | /* |
292 | * Allocated objects start out as write locked to deny any other | |
293 | * syscalls from accessing them until they are committed. See | |
294 | * rdma_alloc_commit_uobject | |
295 | */ | |
296 | atomic_set(&uobj->usecnt, -1); | |
38321256 MB |
297 | kref_init(&uobj->ref); |
298 | ||
299 | return uobj; | |
300 | } | |
301 | ||
302 | static int idr_add_uobj(struct ib_uobject *uobj) | |
303 | { | |
b9b0f345 MW |
304 | /* |
305 | * We start with allocating an idr pointing to NULL. This represents an | |
306 | * object which isn't initialized yet. We'll replace it later on with | |
307 | * the real object once we commit. | |
308 | */ | |
309 | return xa_alloc(&uobj->ufile->idr, &uobj->id, NULL, xa_limit_32b, | |
310 | GFP_KERNEL); | |
38321256 MB |
311 | } |
312 | ||
38321256 | 313 | /* Returns the ib_uobject or an error. The caller should check for IS_ERR. */ |
6ef1c828 | 314 | static struct ib_uobject * |
6b0d08f4 | 315 | lookup_get_idr_uobject(const struct uverbs_api_object *obj, |
9867f5c6 JG |
316 | struct ib_uverbs_file *ufile, s64 id, |
317 | enum rdma_lookup_mode mode) | |
38321256 MB |
318 | { |
319 | struct ib_uobject *uobj; | |
1250c304 JG |
320 | |
321 | if (id < 0 || id > ULONG_MAX) | |
322 | return ERR_PTR(-EINVAL); | |
38321256 MB |
323 | |
324 | rcu_read_lock(); | |
6623e3e3 LR |
325 | /* |
326 | * The idr_find is guaranteed to return a pointer to something that | |
327 | * isn't freed yet, or NULL, as the free after idr_remove goes through | |
328 | * kfree_rcu(). However the object may still have been released and | |
329 | * kfree() could be called at any time. | |
330 | */ | |
b9b0f345 MW |
331 | uobj = xa_load(&ufile->idr, id); |
332 | if (!uobj || !kref_get_unless_zero(&uobj->ref)) | |
6623e3e3 | 333 | uobj = ERR_PTR(-ENOENT); |
38321256 MB |
334 | rcu_read_unlock(); |
335 | return uobj; | |
336 | } | |
337 | ||
9867f5c6 | 338 | static struct ib_uobject * |
6b0d08f4 | 339 | lookup_get_fd_uobject(const struct uverbs_api_object *obj, |
9867f5c6 JG |
340 | struct ib_uverbs_file *ufile, s64 id, |
341 | enum rdma_lookup_mode mode) | |
cf8966b3 | 342 | { |
6b0d08f4 | 343 | const struct uverbs_obj_fd_type *fd_type; |
cf8966b3 MB |
344 | struct file *f; |
345 | struct ib_uobject *uobject; | |
1250c304 | 346 | int fdno = id; |
cf8966b3 | 347 | |
1250c304 JG |
348 | if (fdno != id) |
349 | return ERR_PTR(-EINVAL); | |
350 | ||
9867f5c6 | 351 | if (mode != UVERBS_LOOKUP_READ) |
cf8966b3 MB |
352 | return ERR_PTR(-EOPNOTSUPP); |
353 | ||
6b0d08f4 JG |
354 | if (!obj->type_attrs) |
355 | return ERR_PTR(-EIO); | |
356 | fd_type = | |
357 | container_of(obj->type_attrs, struct uverbs_obj_fd_type, type); | |
358 | ||
1250c304 | 359 | f = fget(fdno); |
cf8966b3 MB |
360 | if (!f) |
361 | return ERR_PTR(-EBADF); | |
362 | ||
363 | uobject = f->private_data; | |
364 | /* | |
f7c8416c JG |
365 | * fget(id) ensures we are not currently running |
366 | * uverbs_uobject_fd_release(), and the caller is expected to ensure | |
367 | * that release is never done while a call to lookup is possible. | |
cf8966b3 | 368 | */ |
0fb00941 | 369 | if (f->f_op != fd_type->fops || uobject->ufile != ufile) { |
cf8966b3 MB |
370 | fput(f); |
371 | return ERR_PTR(-EBADF); | |
372 | } | |
373 | ||
374 | uverbs_uobject_get(uobject); | |
375 | return uobject; | |
376 | } | |
377 | ||
6b0d08f4 | 378 | struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj, |
1250c304 | 379 | struct ib_uverbs_file *ufile, s64 id, |
70f06b26 SR |
380 | enum rdma_lookup_mode mode, |
381 | struct uverbs_attr_bundle *attrs) | |
38321256 MB |
382 | { |
383 | struct ib_uobject *uobj; | |
384 | int ret; | |
385 | ||
b9b0f345 | 386 | if (obj == ERR_PTR(-ENOMSG)) { |
4d7e8cc5 YH |
387 | /* must be UVERBS_IDR_ANY_OBJECT, see uapi_get_object() */ |
388 | uobj = lookup_get_idr_uobject(NULL, ufile, id, mode); | |
389 | if (IS_ERR(uobj)) | |
390 | return uobj; | |
391 | } else { | |
392 | if (IS_ERR(obj)) | |
393 | return ERR_PTR(-EINVAL); | |
394 | ||
395 | uobj = obj->type_class->lookup_get(obj, ufile, id, mode); | |
396 | if (IS_ERR(uobj)) | |
397 | return uobj; | |
398 | ||
399 | if (uobj->uapi_object != obj) { | |
400 | ret = -EINVAL; | |
401 | goto free; | |
402 | } | |
38321256 MB |
403 | } |
404 | ||
cc2e14e6 JG |
405 | /* |
406 | * If we have been disassociated block every command except for | |
407 | * DESTROY based commands. | |
408 | */ | |
409 | if (mode != UVERBS_LOOKUP_DESTROY && | |
410 | !srcu_dereference(ufile->device->ib_dev, | |
411 | &ufile->device->disassociate_srcu)) { | |
412 | ret = -EIO; | |
413 | goto free; | |
414 | } | |
415 | ||
9867f5c6 | 416 | ret = uverbs_try_lock_object(uobj, mode); |
e951747a | 417 | if (ret) |
38321256 | 418 | goto free; |
70f06b26 SR |
419 | if (attrs) |
420 | attrs->context = uobj->context; | |
38321256 MB |
421 | |
422 | return uobj; | |
423 | free: | |
4d7e8cc5 | 424 | uobj->uapi_object->type_class->lookup_put(uobj, mode); |
38321256 MB |
425 | uverbs_uobject_put(uobj); |
426 | return ERR_PTR(ret); | |
427 | } | |
428 | ||
6b0d08f4 JG |
429 | static struct ib_uobject * |
430 | alloc_begin_idr_uobject(const struct uverbs_api_object *obj, | |
39e83af8 | 431 | struct uverbs_attr_bundle *attrs) |
38321256 MB |
432 | { |
433 | int ret; | |
434 | struct ib_uobject *uobj; | |
435 | ||
39e83af8 | 436 | uobj = alloc_uobj(attrs, obj); |
38321256 MB |
437 | if (IS_ERR(uobj)) |
438 | return uobj; | |
439 | ||
440 | ret = idr_add_uobj(uobj); | |
441 | if (ret) | |
442 | goto uobj_put; | |
443 | ||
22fa27fb | 444 | ret = ib_rdmacg_try_charge(&uobj->cg_obj, uobj->context->device, |
38321256 MB |
445 | RDMACG_RESOURCE_HCA_OBJECT); |
446 | if (ret) | |
b9b0f345 | 447 | goto remove; |
38321256 MB |
448 | |
449 | return uobj; | |
450 | ||
b9b0f345 | 451 | remove: |
39e83af8 | 452 | xa_erase(&attrs->ufile->idr, uobj->id); |
38321256 MB |
453 | uobj_put: |
454 | uverbs_uobject_put(uobj); | |
455 | return ERR_PTR(ret); | |
456 | } | |
457 | ||
6b0d08f4 JG |
458 | static struct ib_uobject * |
459 | alloc_begin_fd_uobject(const struct uverbs_api_object *obj, | |
39e83af8 | 460 | struct uverbs_attr_bundle *attrs) |
cf8966b3 | 461 | { |
849e1490 JG |
462 | const struct uverbs_obj_fd_type *fd_type = |
463 | container_of(obj->type_attrs, struct uverbs_obj_fd_type, type); | |
cf8966b3 MB |
464 | int new_fd; |
465 | struct ib_uobject *uobj; | |
849e1490 JG |
466 | struct file *filp; |
467 | ||
c485b19d JG |
468 | if (WARN_ON(fd_type->fops->release != &uverbs_uobject_fd_release && |
469 | fd_type->fops->release != &uverbs_async_event_release)) | |
849e1490 | 470 | return ERR_PTR(-EINVAL); |
cf8966b3 MB |
471 | |
472 | new_fd = get_unused_fd_flags(O_CLOEXEC); | |
473 | if (new_fd < 0) | |
474 | return ERR_PTR(new_fd); | |
475 | ||
39e83af8 | 476 | uobj = alloc_uobj(attrs, obj); |
849e1490 JG |
477 | if (IS_ERR(uobj)) |
478 | goto err_fd; | |
479 | ||
480 | /* Note that uverbs_uobject_fd_release() is called during abort */ | |
481 | filp = anon_inode_getfile(fd_type->name, fd_type->fops, NULL, | |
482 | fd_type->flags); | |
483 | if (IS_ERR(filp)) { | |
83a26702 | 484 | uverbs_uobject_put(uobj); |
849e1490 | 485 | uobj = ERR_CAST(filp); |
83a26702 | 486 | goto err_fd; |
cf8966b3 | 487 | } |
849e1490 | 488 | uobj->object = filp; |
cf8966b3 | 489 | |
d0259e82 | 490 | uobj->id = new_fd; |
849e1490 | 491 | return uobj; |
cf8966b3 | 492 | |
849e1490 JG |
493 | err_fd: |
494 | put_unused_fd(new_fd); | |
cf8966b3 MB |
495 | return uobj; |
496 | } | |
497 | ||
6b0d08f4 | 498 | struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj, |
70f06b26 | 499 | struct uverbs_attr_bundle *attrs) |
38321256 | 500 | { |
39e83af8 | 501 | struct ib_uverbs_file *ufile = attrs->ufile; |
1e857e65 JG |
502 | struct ib_uobject *ret; |
503 | ||
4d7e8cc5 | 504 | if (IS_ERR(obj)) |
6b0d08f4 JG |
505 | return ERR_PTR(-EINVAL); |
506 | ||
1e857e65 JG |
507 | /* |
508 | * The hw_destroy_rwsem is held across the entire object creation and | |
509 | * released during rdma_alloc_commit_uobject or | |
510 | * rdma_alloc_abort_uobject | |
511 | */ | |
512 | if (!down_read_trylock(&ufile->hw_destroy_rwsem)) | |
513 | return ERR_PTR(-EIO); | |
514 | ||
39e83af8 | 515 | ret = obj->type_class->alloc_begin(obj, attrs); |
1e857e65 JG |
516 | if (IS_ERR(ret)) { |
517 | up_read(&ufile->hw_destroy_rwsem); | |
518 | return ret; | |
519 | } | |
520 | return ret; | |
38321256 MB |
521 | } |
522 | ||
87ad80ab JG |
523 | static void alloc_abort_idr_uobject(struct ib_uobject *uobj) |
524 | { | |
525 | ib_rdmacg_uncharge(&uobj->cg_obj, uobj->context->device, | |
526 | RDMACG_RESOURCE_HCA_OBJECT); | |
527 | ||
b9b0f345 | 528 | xa_erase(&uobj->ufile->idr, uobj->id); |
87ad80ab JG |
529 | } |
530 | ||
0f50d88a | 531 | static int __must_check destroy_hw_idr_uobject(struct ib_uobject *uobj, |
a6a3797d SR |
532 | enum rdma_remove_reason why, |
533 | struct uverbs_attr_bundle *attrs) | |
38321256 MB |
534 | { |
535 | const struct uverbs_obj_idr_type *idr_type = | |
6b0d08f4 JG |
536 | container_of(uobj->uapi_object->type_attrs, |
537 | struct uverbs_obj_idr_type, type); | |
a6a3797d | 538 | int ret = idr_type->destroy_object(uobj, why, attrs); |
38321256 MB |
539 | |
540 | /* | |
541 | * We can only fail gracefully if the user requested to destroy the | |
1c77483e YH |
542 | * object or when a retry may be called upon an error. |
543 | * In the rest of the cases, just remove whatever you can. | |
38321256 | 544 | */ |
1c77483e | 545 | if (ib_is_destroy_retryable(ret, why, uobj)) |
38321256 MB |
546 | return ret; |
547 | ||
87ad80ab JG |
548 | if (why == RDMA_REMOVE_ABORT) |
549 | return 0; | |
5671f79b | 550 | |
0f50d88a JG |
551 | ib_rdmacg_uncharge(&uobj->cg_obj, uobj->context->device, |
552 | RDMACG_RESOURCE_HCA_OBJECT); | |
38321256 | 553 | |
87ad80ab | 554 | return 0; |
38321256 MB |
555 | } |
556 | ||
0f50d88a JG |
557 | static void remove_handle_idr_uobject(struct ib_uobject *uobj) |
558 | { | |
b9b0f345 | 559 | xa_erase(&uobj->ufile->idr, uobj->id); |
0f50d88a JG |
560 | /* Matches the kref in alloc_commit_idr_uobject */ |
561 | uverbs_uobject_put(uobj); | |
562 | } | |
563 | ||
cf8966b3 MB |
564 | static void alloc_abort_fd_uobject(struct ib_uobject *uobj) |
565 | { | |
849e1490 JG |
566 | struct file *filp = uobj->object; |
567 | ||
568 | fput(filp); | |
aba94548 | 569 | put_unused_fd(uobj->id); |
cf8966b3 MB |
570 | } |
571 | ||
0f50d88a | 572 | static int __must_check destroy_hw_fd_uobject(struct ib_uobject *uobj, |
a6a3797d SR |
573 | enum rdma_remove_reason why, |
574 | struct uverbs_attr_bundle *attrs) | |
cf8966b3 | 575 | { |
6b0d08f4 JG |
576 | const struct uverbs_obj_fd_type *fd_type = container_of( |
577 | uobj->uapi_object->type_attrs, struct uverbs_obj_fd_type, type); | |
f7c8416c | 578 | int ret = fd_type->destroy_object(uobj, why); |
cf8966b3 | 579 | |
1c77483e | 580 | if (ib_is_destroy_retryable(ret, why, uobj)) |
cf8966b3 MB |
581 | return ret; |
582 | ||
87ad80ab | 583 | return 0; |
38321256 MB |
584 | } |
585 | ||
0f50d88a JG |
586 | static void remove_handle_fd_uobject(struct ib_uobject *uobj) |
587 | { | |
588 | } | |
589 | ||
849e1490 | 590 | static void alloc_commit_idr_uobject(struct ib_uobject *uobj) |
38321256 | 591 | { |
c561c288 | 592 | struct ib_uverbs_file *ufile = uobj->ufile; |
b9b0f345 | 593 | void *old; |
c561c288 | 594 | |
38321256 MB |
595 | /* |
596 | * We already allocated this IDR with a NULL object, so | |
597 | * this shouldn't fail. | |
c561c288 | 598 | * |
b9b0f345 | 599 | * NOTE: Storing the uobj transfers our kref on uobj to the XArray. |
c561c288 | 600 | * It will be put by remove_commit_idr_uobject() |
38321256 | 601 | */ |
b9b0f345 MW |
602 | old = xa_store(&ufile->idr, uobj->id, uobj, GFP_KERNEL); |
603 | WARN_ON(old != NULL); | |
38321256 MB |
604 | } |
605 | ||
849e1490 | 606 | static void alloc_commit_fd_uobject(struct ib_uobject *uobj) |
cf8966b3 | 607 | { |
c561c288 | 608 | int fd = uobj->id; |
849e1490 | 609 | struct file *filp = uobj->object; |
aba94548 | 610 | |
f7c8416c | 611 | /* Matching put will be done in uverbs_uobject_fd_release() */ |
aba94548 | 612 | kref_get(&uobj->ufile->ref); |
c561c288 | 613 | |
cf8966b3 | 614 | /* This shouldn't be used anymore. Use the file object instead */ |
d0259e82 | 615 | uobj->id = 0; |
c561c288 | 616 | |
c561c288 JG |
617 | /* |
618 | * NOTE: Once we install the file we loose ownership of our kref on | |
f7c8416c | 619 | * uobj. It will be put by uverbs_uobject_fd_release() |
c561c288 | 620 | */ |
849e1490 | 621 | filp->private_data = uobj; |
aba94548 | 622 | fd_install(fd, filp); |
cf8966b3 MB |
623 | } |
624 | ||
c561c288 JG |
625 | /* |
626 | * In all cases rdma_alloc_commit_uobject() consumes the kref to uobj and the | |
2c96eb7d JG |
627 | * caller can no longer assume uobj is valid. If this function fails it |
628 | * destroys the uboject, including the attached HW object. | |
c561c288 | 629 | */ |
849e1490 JG |
630 | void rdma_alloc_commit_uobject(struct ib_uobject *uobj, |
631 | struct uverbs_attr_bundle *attrs) | |
38321256 | 632 | { |
feec576a | 633 | struct ib_uverbs_file *ufile = attrs->ufile; |
6a5e9c88 | 634 | |
aba94548 | 635 | /* alloc_commit consumes the uobj kref */ |
849e1490 | 636 | uobj->uapi_object->type_class->alloc_commit(uobj); |
d9dc7a35 | 637 | |
5671f79b JG |
638 | /* kref is held so long as the uobj is on the uobj list. */ |
639 | uverbs_uobject_get(uobj); | |
87064277 | 640 | spin_lock_irq(&ufile->uobjects_lock); |
6a5e9c88 | 641 | list_add(&uobj->list, &ufile->uobjects); |
87064277 | 642 | spin_unlock_irq(&ufile->uobjects_lock); |
8efe991e | 643 | |
aba94548 JG |
644 | /* matches atomic_set(-1) in alloc_uobj */ |
645 | atomic_set(&uobj->usecnt, 0); | |
646 | ||
1e857e65 | 647 | /* Matches the down_read in rdma_alloc_begin_uobject */ |
87064277 | 648 | up_read(&ufile->hw_destroy_rwsem); |
38321256 MB |
649 | } |
650 | ||
5671f79b JG |
651 | /* |
652 | * This consumes the kref for uobj. It is up to the caller to unwind the HW | |
653 | * object and anything else connected to uobj before calling this. | |
654 | */ | |
a6a3797d SR |
655 | void rdma_alloc_abort_uobject(struct ib_uobject *uobj, |
656 | struct uverbs_attr_bundle *attrs) | |
38321256 | 657 | { |
1e857e65 JG |
658 | struct ib_uverbs_file *ufile = uobj->ufile; |
659 | ||
a6a3797d | 660 | uverbs_destroy_uobject(uobj, RDMA_REMOVE_ABORT, attrs); |
1e857e65 JG |
661 | |
662 | /* Matches the down_read in rdma_alloc_begin_uobject */ | |
663 | up_read(&ufile->hw_destroy_rwsem); | |
38321256 MB |
664 | } |
665 | ||
9867f5c6 JG |
666 | static void lookup_put_idr_uobject(struct ib_uobject *uobj, |
667 | enum rdma_lookup_mode mode) | |
38321256 MB |
668 | { |
669 | } | |
670 | ||
9867f5c6 JG |
671 | static void lookup_put_fd_uobject(struct ib_uobject *uobj, |
672 | enum rdma_lookup_mode mode) | |
cf8966b3 MB |
673 | { |
674 | struct file *filp = uobj->object; | |
675 | ||
9867f5c6 | 676 | WARN_ON(mode != UVERBS_LOOKUP_READ); |
f7c8416c JG |
677 | /* |
678 | * This indirectly calls uverbs_uobject_fd_release() and free the | |
679 | * object | |
680 | */ | |
cf8966b3 MB |
681 | fput(filp); |
682 | } | |
683 | ||
9867f5c6 JG |
684 | void rdma_lookup_put_uobject(struct ib_uobject *uobj, |
685 | enum rdma_lookup_mode mode) | |
38321256 | 686 | { |
9867f5c6 | 687 | assert_uverbs_usecnt(uobj, mode); |
38321256 MB |
688 | /* |
689 | * In order to unlock an object, either decrease its usecnt for | |
30004b86 | 690 | * read access or zero it in case of exclusive access. See |
38321256 MB |
691 | * uverbs_try_lock_object for locking schema information. |
692 | */ | |
9867f5c6 JG |
693 | switch (mode) { |
694 | case UVERBS_LOOKUP_READ: | |
38321256 | 695 | atomic_dec(&uobj->usecnt); |
9867f5c6 JG |
696 | break; |
697 | case UVERBS_LOOKUP_WRITE: | |
38321256 | 698 | atomic_set(&uobj->usecnt, 0); |
9867f5c6 | 699 | break; |
7452a3c7 JG |
700 | case UVERBS_LOOKUP_DESTROY: |
701 | break; | |
9867f5c6 | 702 | } |
38321256 | 703 | |
f0abc761 | 704 | uobj->uapi_object->type_class->lookup_put(uobj, mode); |
5671f79b | 705 | /* Pairs with the kref obtained by type->lookup_get */ |
38321256 MB |
706 | uverbs_uobject_put(uobj); |
707 | } | |
708 | ||
0f50d88a JG |
709 | void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile) |
710 | { | |
b9b0f345 | 711 | xa_init_flags(&ufile->idr, XA_FLAGS_ALLOC); |
0f50d88a JG |
712 | } |
713 | ||
714 | void release_ufile_idr_uobject(struct ib_uverbs_file *ufile) | |
715 | { | |
716 | struct ib_uobject *entry; | |
b9b0f345 | 717 | unsigned long id; |
0f50d88a JG |
718 | |
719 | /* | |
720 | * At this point uverbs_cleanup_ufile() is guaranteed to have run, and | |
b9b0f345 | 721 | * there are no HW objects left, however the xarray is still populated |
0f50d88a JG |
722 | * with anything that has not been cleaned up by userspace. Since the |
723 | * kref on ufile is 0, nothing is allowed to call lookup_get. | |
724 | * | |
725 | * This is an optimized equivalent to remove_handle_idr_uobject | |
726 | */ | |
b9b0f345 | 727 | xa_for_each(&ufile->idr, id, entry) { |
0f50d88a JG |
728 | WARN_ON(entry->object); |
729 | uverbs_uobject_put(entry); | |
730 | } | |
731 | ||
b9b0f345 | 732 | xa_destroy(&ufile->idr); |
0f50d88a JG |
733 | } |
734 | ||
38321256 MB |
735 | const struct uverbs_obj_type_class uverbs_idr_class = { |
736 | .alloc_begin = alloc_begin_idr_uobject, | |
737 | .lookup_get = lookup_get_idr_uobject, | |
738 | .alloc_commit = alloc_commit_idr_uobject, | |
739 | .alloc_abort = alloc_abort_idr_uobject, | |
740 | .lookup_put = lookup_put_idr_uobject, | |
0f50d88a JG |
741 | .destroy_hw = destroy_hw_idr_uobject, |
742 | .remove_handle = remove_handle_idr_uobject, | |
38321256 | 743 | }; |
1114b0a8 | 744 | EXPORT_SYMBOL(uverbs_idr_class); |
38321256 | 745 | |
f7c8416c JG |
746 | /* |
747 | * Users of UVERBS_TYPE_ALLOC_FD should set this function as the struct | |
748 | * file_operations release method. | |
749 | */ | |
750 | int uverbs_uobject_fd_release(struct inode *inode, struct file *filp) | |
cf8966b3 | 751 | { |
849e1490 JG |
752 | struct ib_uverbs_file *ufile; |
753 | struct ib_uobject *uobj; | |
754 | ||
755 | /* | |
756 | * This can only happen if the fput came from alloc_abort_fd_uobject() | |
757 | */ | |
758 | if (!filp->private_data) | |
759 | return 0; | |
760 | uobj = filp->private_data; | |
761 | ufile = uobj->ufile; | |
e6d5d5dd | 762 | |
87064277 | 763 | if (down_read_trylock(&ufile->hw_destroy_rwsem)) { |
849e1490 JG |
764 | struct uverbs_attr_bundle attrs = { |
765 | .context = uobj->context, | |
766 | .ufile = ufile, | |
767 | }; | |
768 | ||
87ad80ab JG |
769 | /* |
770 | * lookup_get_fd_uobject holds the kref on the struct file any | |
771 | * time a FD uobj is locked, which prevents this release | |
772 | * method from being invoked. Meaning we can always get the | |
773 | * write lock here, or we have a kernel bug. | |
774 | */ | |
9867f5c6 | 775 | WARN_ON(uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE)); |
a6a3797d | 776 | uverbs_destroy_uobject(uobj, RDMA_REMOVE_CLOSE, &attrs); |
87064277 | 777 | up_read(&ufile->hw_destroy_rwsem); |
e6d5d5dd JG |
778 | } |
779 | ||
849e1490 | 780 | /* Matches the get in alloc_commit_fd_uobject() */ |
e6d5d5dd | 781 | kref_put(&ufile->ref, ib_uverbs_release_file); |
cf8966b3 | 782 | |
5671f79b | 783 | /* Pairs with filp->private_data in alloc_begin_fd_uobject */ |
d0259e82 | 784 | uverbs_uobject_put(uobj); |
f7c8416c | 785 | return 0; |
cf8966b3 | 786 | } |
f7c8416c | 787 | EXPORT_SYMBOL(uverbs_uobject_fd_release); |
cf8966b3 | 788 | |
e951747a JG |
789 | /* |
790 | * Drop the ucontext off the ufile and completely disconnect it from the | |
791 | * ib_device | |
792 | */ | |
793 | static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile, | |
794 | enum rdma_remove_reason reason) | |
795 | { | |
796 | struct ib_ucontext *ucontext = ufile->ucontext; | |
ce92db1c | 797 | struct ib_device *ib_dev = ucontext->device; |
e951747a | 798 | |
ce92db1c JG |
799 | /* |
800 | * If we are closing the FD then the user mmap VMAs must have | |
801 | * already been destroyed as they hold on to the filep, otherwise | |
802 | * they need to be zap'd. | |
803 | */ | |
5f9794dc JG |
804 | if (reason == RDMA_REMOVE_DRIVER_REMOVE) { |
805 | uverbs_user_mmap_disassociate(ufile); | |
3023a1e9 KH |
806 | if (ib_dev->ops.disassociate_ucontext) |
807 | ib_dev->ops.disassociate_ucontext(ucontext); | |
5f9794dc | 808 | } |
e951747a | 809 | |
ce92db1c | 810 | ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev, |
e951747a JG |
811 | RDMACG_RESOURCE_HCA_HANDLE); |
812 | ||
12d23a91 LR |
813 | rdma_restrack_del(&ucontext->res); |
814 | ||
a2a074ef | 815 | ib_dev->ops.dealloc_ucontext(ucontext); |
3411f9f0 | 816 | WARN_ON(!xa_empty(&ucontext->mmap_xa)); |
a2a074ef | 817 | kfree(ucontext); |
e951747a JG |
818 | |
819 | ufile->ucontext = NULL; | |
820 | } | |
821 | ||
6ef1c828 JG |
822 | static int __uverbs_cleanup_ufile(struct ib_uverbs_file *ufile, |
823 | enum rdma_remove_reason reason) | |
38321256 | 824 | { |
1c77483e YH |
825 | struct ib_uobject *obj, *next_obj; |
826 | int ret = -EINVAL; | |
a6a3797d | 827 | struct uverbs_attr_bundle attrs = { .ufile = ufile }; |
38321256 | 828 | |
1c77483e YH |
829 | /* |
830 | * This shouldn't run while executing other commands on this | |
831 | * context. Thus, the only thing we should take care of is | |
832 | * releasing a FD while traversing this list. The FD could be | |
833 | * closed and released from the _release fop of this FD. | |
834 | * In order to mitigate this, we add a lock. | |
835 | * We take and release the lock per traversal in order to let | |
836 | * other threads (which might still use the FDs) chance to run. | |
837 | */ | |
6a5e9c88 | 838 | list_for_each_entry_safe(obj, next_obj, &ufile->uobjects, list) { |
a6a3797d | 839 | attrs.context = obj->context; |
1c77483e YH |
840 | /* |
841 | * if we hit this WARN_ON, that means we are | |
842 | * racing with a lookup_get. | |
843 | */ | |
9867f5c6 | 844 | WARN_ON(uverbs_try_lock_object(obj, UVERBS_LOOKUP_WRITE)); |
a6a3797d | 845 | if (!uverbs_destroy_uobject(obj, reason, &attrs)) |
87ad80ab | 846 | ret = 0; |
e4ff3d22 AK |
847 | else |
848 | atomic_set(&obj->usecnt, 0); | |
1c77483e | 849 | } |
1c77483e YH |
850 | return ret; |
851 | } | |
852 | ||
e951747a | 853 | /* |
da57db25 | 854 | * Destroy the uncontext and every uobject associated with it. |
e951747a JG |
855 | * |
856 | * This is internally locked and can be called in parallel from multiple | |
857 | * contexts. | |
858 | */ | |
859 | void uverbs_destroy_ufile_hw(struct ib_uverbs_file *ufile, | |
860 | enum rdma_remove_reason reason) | |
1c77483e | 861 | { |
e951747a | 862 | down_write(&ufile->hw_destroy_rwsem); |
6a5e9c88 | 863 | |
38321256 | 864 | /* |
e951747a JG |
865 | * If a ucontext was never created then we can't have any uobjects to |
866 | * cleanup, nothing to do. | |
38321256 | 867 | */ |
e951747a JG |
868 | if (!ufile->ucontext) |
869 | goto done; | |
870 | ||
871 | ufile->ucontext->closing = true; | |
6a5e9c88 JG |
872 | ufile->ucontext->cleanup_retryable = true; |
873 | while (!list_empty(&ufile->uobjects)) | |
6ef1c828 | 874 | if (__uverbs_cleanup_ufile(ufile, reason)) { |
1c77483e YH |
875 | /* |
876 | * No entry was cleaned-up successfully during this | |
877 | * iteration | |
878 | */ | |
879 | break; | |
880 | } | |
38321256 | 881 | |
6a5e9c88 JG |
882 | ufile->ucontext->cleanup_retryable = false; |
883 | if (!list_empty(&ufile->uobjects)) | |
6ef1c828 | 884 | __uverbs_cleanup_ufile(ufile, reason); |
38321256 | 885 | |
e951747a JG |
886 | ufile_destroy_ucontext(ufile, reason); |
887 | ||
888 | done: | |
87064277 | 889 | up_write(&ufile->hw_destroy_rwsem); |
38321256 MB |
890 | } |
891 | ||
cf8966b3 MB |
892 | const struct uverbs_obj_type_class uverbs_fd_class = { |
893 | .alloc_begin = alloc_begin_fd_uobject, | |
894 | .lookup_get = lookup_get_fd_uobject, | |
895 | .alloc_commit = alloc_commit_fd_uobject, | |
896 | .alloc_abort = alloc_abort_fd_uobject, | |
897 | .lookup_put = lookup_put_fd_uobject, | |
0f50d88a JG |
898 | .destroy_hw = destroy_hw_fd_uobject, |
899 | .remove_handle = remove_handle_fd_uobject, | |
cf8966b3 | 900 | }; |
1114b0a8 | 901 | EXPORT_SYMBOL(uverbs_fd_class); |
cf8966b3 | 902 | |
6ef1c828 | 903 | struct ib_uobject * |
70f06b26 SR |
904 | uverbs_get_uobject_from_file(u16 object_id, enum uverbs_obj_access access, |
905 | s64 id, struct uverbs_attr_bundle *attrs) | |
a0aa309c | 906 | { |
6b0d08f4 | 907 | const struct uverbs_api_object *obj = |
70f06b26 | 908 | uapi_get_object(attrs->ufile->device->uapi, object_id); |
6b0d08f4 | 909 | |
a0aa309c MB |
910 | switch (access) { |
911 | case UVERBS_ACCESS_READ: | |
70f06b26 SR |
912 | return rdma_lookup_get_uobject(obj, attrs->ufile, id, |
913 | UVERBS_LOOKUP_READ, attrs); | |
a0aa309c | 914 | case UVERBS_ACCESS_DESTROY: |
7452a3c7 | 915 | /* Actual destruction is done inside uverbs_handle_method */ |
70f06b26 SR |
916 | return rdma_lookup_get_uobject(obj, attrs->ufile, id, |
917 | UVERBS_LOOKUP_DESTROY, attrs); | |
a0aa309c | 918 | case UVERBS_ACCESS_WRITE: |
70f06b26 SR |
919 | return rdma_lookup_get_uobject(obj, attrs->ufile, id, |
920 | UVERBS_LOOKUP_WRITE, attrs); | |
a0aa309c | 921 | case UVERBS_ACCESS_NEW: |
39e83af8 | 922 | return rdma_alloc_begin_uobject(obj, attrs); |
a0aa309c MB |
923 | default: |
924 | WARN_ON(true); | |
925 | return ERR_PTR(-EOPNOTSUPP); | |
926 | } | |
927 | } | |
928 | ||
849e1490 JG |
929 | void uverbs_finalize_object(struct ib_uobject *uobj, |
930 | enum uverbs_obj_access access, bool commit, | |
931 | struct uverbs_attr_bundle *attrs) | |
a0aa309c | 932 | { |
a0aa309c MB |
933 | /* |
934 | * refcounts should be handled at the object level and not at the | |
935 | * uobject level. Refcounts of the objects themselves are done in | |
936 | * handlers. | |
937 | */ | |
938 | ||
939 | switch (access) { | |
940 | case UVERBS_ACCESS_READ: | |
9867f5c6 | 941 | rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_READ); |
a0aa309c MB |
942 | break; |
943 | case UVERBS_ACCESS_WRITE: | |
9867f5c6 | 944 | rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE); |
a0aa309c MB |
945 | break; |
946 | case UVERBS_ACCESS_DESTROY: | |
7452a3c7 JG |
947 | if (uobj) |
948 | rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_DESTROY); | |
a0aa309c MB |
949 | break; |
950 | case UVERBS_ACCESS_NEW: | |
951 | if (commit) | |
849e1490 | 952 | rdma_alloc_commit_uobject(uobj, attrs); |
a0aa309c | 953 | else |
a6a3797d | 954 | rdma_alloc_abort_uobject(uobj, attrs); |
a0aa309c MB |
955 | break; |
956 | default: | |
957 | WARN_ON(true); | |
a0aa309c | 958 | } |
a0aa309c | 959 | } |