0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/file.h>
0034 #include <linux/anon_inodes.h>
0035 #include <linux/sched/mm.h>
0036 #include <rdma/ib_verbs.h>
0037 #include <rdma/uverbs_types.h>
0038 #include <linux/rcupdate.h>
0039 #include <rdma/uverbs_ioctl.h>
0040 #include <rdma/rdma_user_ioctl.h>
0041 #include "uverbs.h"
0042 #include "core_priv.h"
0043 #include "rdma_core.h"
0044
0045 static void uverbs_uobject_free(struct kref *ref)
0046 {
0047 kfree_rcu(container_of(ref, struct ib_uobject, ref), rcu);
0048 }
0049
0050
0051
0052
0053
0054
0055 void uverbs_uobject_put(struct ib_uobject *uobject)
0056 {
0057 kref_put(&uobject->ref, uverbs_uobject_free);
0058 }
0059 EXPORT_SYMBOL(uverbs_uobject_put);
0060
0061 static int uverbs_try_lock_object(struct ib_uobject *uobj,
0062 enum rdma_lookup_mode mode)
0063 {
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 switch (mode) {
0076 case UVERBS_LOOKUP_READ:
0077 return atomic_fetch_add_unless(&uobj->usecnt, 1, -1) == -1 ?
0078 -EBUSY : 0;
0079 case UVERBS_LOOKUP_WRITE:
0080
0081 return atomic_cmpxchg(&uobj->usecnt, 0, -1) == 0 ? 0 : -EBUSY;
0082 case UVERBS_LOOKUP_DESTROY:
0083 return 0;
0084 }
0085 return 0;
0086 }
0087
0088 static void assert_uverbs_usecnt(struct ib_uobject *uobj,
0089 enum rdma_lookup_mode mode)
0090 {
0091 #ifdef CONFIG_LOCKDEP
0092 switch (mode) {
0093 case UVERBS_LOOKUP_READ:
0094 WARN_ON(atomic_read(&uobj->usecnt) <= 0);
0095 break;
0096 case UVERBS_LOOKUP_WRITE:
0097 WARN_ON(atomic_read(&uobj->usecnt) != -1);
0098 break;
0099 case UVERBS_LOOKUP_DESTROY:
0100 break;
0101 }
0102 #endif
0103 }
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122 static int uverbs_destroy_uobject(struct ib_uobject *uobj,
0123 enum rdma_remove_reason reason,
0124 struct uverbs_attr_bundle *attrs)
0125 {
0126 struct ib_uverbs_file *ufile = attrs->ufile;
0127 unsigned long flags;
0128 int ret;
0129
0130 lockdep_assert_held(&ufile->hw_destroy_rwsem);
0131 assert_uverbs_usecnt(uobj, UVERBS_LOOKUP_WRITE);
0132
0133 if (reason == RDMA_REMOVE_ABORT) {
0134 WARN_ON(!list_empty(&uobj->list));
0135 WARN_ON(!uobj->context);
0136 uobj->uapi_object->type_class->alloc_abort(uobj);
0137 } else if (uobj->object) {
0138 ret = uobj->uapi_object->type_class->destroy_hw(uobj, reason,
0139 attrs);
0140 if (ret)
0141
0142 return ret;
0143
0144 uobj->object = NULL;
0145 }
0146
0147 uobj->context = NULL;
0148
0149
0150
0151
0152
0153
0154 if (reason != RDMA_REMOVE_DESTROY)
0155 atomic_set(&uobj->usecnt, 0);
0156 else
0157 uobj->uapi_object->type_class->remove_handle(uobj);
0158
0159 if (!list_empty(&uobj->list)) {
0160 spin_lock_irqsave(&ufile->uobjects_lock, flags);
0161 list_del_init(&uobj->list);
0162 spin_unlock_irqrestore(&ufile->uobjects_lock, flags);
0163
0164
0165
0166
0167
0168 uverbs_uobject_put(uobj);
0169 }
0170
0171
0172
0173
0174
0175 if (reason == RDMA_REMOVE_ABORT)
0176 uverbs_uobject_put(uobj);
0177
0178 return 0;
0179 }
0180
0181
0182
0183
0184
0185
0186
0187
0188 int uobj_destroy(struct ib_uobject *uobj, struct uverbs_attr_bundle *attrs)
0189 {
0190 struct ib_uverbs_file *ufile = attrs->ufile;
0191 int ret;
0192
0193 down_read(&ufile->hw_destroy_rwsem);
0194
0195
0196
0197
0198
0199
0200
0201
0202 ret = uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE);
0203 if (ret)
0204 goto out_unlock;
0205
0206 ret = uverbs_destroy_uobject(uobj, RDMA_REMOVE_DESTROY, attrs);
0207 if (ret) {
0208 atomic_set(&uobj->usecnt, 0);
0209 goto out_unlock;
0210 }
0211
0212 out_unlock:
0213 up_read(&ufile->hw_destroy_rwsem);
0214 return ret;
0215 }
0216
0217
0218
0219
0220
0221
0222 struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
0223 u32 id, struct uverbs_attr_bundle *attrs)
0224 {
0225 struct ib_uobject *uobj;
0226 int ret;
0227
0228 uobj = rdma_lookup_get_uobject(obj, attrs->ufile, id,
0229 UVERBS_LOOKUP_DESTROY, attrs);
0230 if (IS_ERR(uobj))
0231 return uobj;
0232
0233 ret = uobj_destroy(uobj, attrs);
0234 if (ret) {
0235 rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_DESTROY);
0236 return ERR_PTR(ret);
0237 }
0238
0239 return uobj;
0240 }
0241
0242
0243
0244
0245
0246 int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id,
0247 struct uverbs_attr_bundle *attrs)
0248 {
0249 struct ib_uobject *uobj;
0250
0251 uobj = __uobj_get_destroy(obj, id, attrs);
0252 if (IS_ERR(uobj))
0253 return PTR_ERR(uobj);
0254 uobj_put_destroy(uobj);
0255 return 0;
0256 }
0257
0258
0259 static struct ib_uobject *alloc_uobj(struct uverbs_attr_bundle *attrs,
0260 const struct uverbs_api_object *obj)
0261 {
0262 struct ib_uverbs_file *ufile = attrs->ufile;
0263 struct ib_uobject *uobj;
0264
0265 if (!attrs->context) {
0266 struct ib_ucontext *ucontext =
0267 ib_uverbs_get_ucontext_file(ufile);
0268
0269 if (IS_ERR(ucontext))
0270 return ERR_CAST(ucontext);
0271 attrs->context = ucontext;
0272 }
0273
0274 uobj = kzalloc(obj->type_attrs->obj_size, GFP_KERNEL);
0275 if (!uobj)
0276 return ERR_PTR(-ENOMEM);
0277
0278
0279
0280
0281 uobj->ufile = ufile;
0282 uobj->context = attrs->context;
0283 INIT_LIST_HEAD(&uobj->list);
0284 uobj->uapi_object = obj;
0285
0286
0287
0288
0289
0290 atomic_set(&uobj->usecnt, -1);
0291 kref_init(&uobj->ref);
0292
0293 return uobj;
0294 }
0295
0296 static int idr_add_uobj(struct ib_uobject *uobj)
0297 {
0298
0299
0300
0301
0302
0303 return xa_alloc(&uobj->ufile->idr, &uobj->id, NULL, xa_limit_32b,
0304 GFP_KERNEL);
0305 }
0306
0307
0308 static struct ib_uobject *
0309 lookup_get_idr_uobject(const struct uverbs_api_object *obj,
0310 struct ib_uverbs_file *ufile, s64 id,
0311 enum rdma_lookup_mode mode)
0312 {
0313 struct ib_uobject *uobj;
0314
0315 if (id < 0 || id > ULONG_MAX)
0316 return ERR_PTR(-EINVAL);
0317
0318 rcu_read_lock();
0319
0320
0321
0322
0323
0324
0325 uobj = xa_load(&ufile->idr, id);
0326 if (!uobj || !kref_get_unless_zero(&uobj->ref))
0327 uobj = ERR_PTR(-ENOENT);
0328 rcu_read_unlock();
0329 return uobj;
0330 }
0331
0332 static struct ib_uobject *
0333 lookup_get_fd_uobject(const struct uverbs_api_object *obj,
0334 struct ib_uverbs_file *ufile, s64 id,
0335 enum rdma_lookup_mode mode)
0336 {
0337 const struct uverbs_obj_fd_type *fd_type;
0338 struct file *f;
0339 struct ib_uobject *uobject;
0340 int fdno = id;
0341
0342 if (fdno != id)
0343 return ERR_PTR(-EINVAL);
0344
0345 if (mode != UVERBS_LOOKUP_READ)
0346 return ERR_PTR(-EOPNOTSUPP);
0347
0348 if (!obj->type_attrs)
0349 return ERR_PTR(-EIO);
0350 fd_type =
0351 container_of(obj->type_attrs, struct uverbs_obj_fd_type, type);
0352
0353 f = fget(fdno);
0354 if (!f)
0355 return ERR_PTR(-EBADF);
0356
0357 uobject = f->private_data;
0358
0359
0360
0361
0362
0363 if (f->f_op != fd_type->fops || uobject->ufile != ufile) {
0364 fput(f);
0365 return ERR_PTR(-EBADF);
0366 }
0367
0368 uverbs_uobject_get(uobject);
0369 return uobject;
0370 }
0371
0372 struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj,
0373 struct ib_uverbs_file *ufile, s64 id,
0374 enum rdma_lookup_mode mode,
0375 struct uverbs_attr_bundle *attrs)
0376 {
0377 struct ib_uobject *uobj;
0378 int ret;
0379
0380 if (obj == ERR_PTR(-ENOMSG)) {
0381
0382 uobj = lookup_get_idr_uobject(NULL, ufile, id, mode);
0383 if (IS_ERR(uobj))
0384 return uobj;
0385 } else {
0386 if (IS_ERR(obj))
0387 return ERR_PTR(-EINVAL);
0388
0389 uobj = obj->type_class->lookup_get(obj, ufile, id, mode);
0390 if (IS_ERR(uobj))
0391 return uobj;
0392
0393 if (uobj->uapi_object != obj) {
0394 ret = -EINVAL;
0395 goto free;
0396 }
0397 }
0398
0399
0400
0401
0402
0403 if (mode != UVERBS_LOOKUP_DESTROY &&
0404 !srcu_dereference(ufile->device->ib_dev,
0405 &ufile->device->disassociate_srcu)) {
0406 ret = -EIO;
0407 goto free;
0408 }
0409
0410 ret = uverbs_try_lock_object(uobj, mode);
0411 if (ret)
0412 goto free;
0413 if (attrs)
0414 attrs->context = uobj->context;
0415
0416 return uobj;
0417 free:
0418 uobj->uapi_object->type_class->lookup_put(uobj, mode);
0419 uverbs_uobject_put(uobj);
0420 return ERR_PTR(ret);
0421 }
0422
0423 static struct ib_uobject *
0424 alloc_begin_idr_uobject(const struct uverbs_api_object *obj,
0425 struct uverbs_attr_bundle *attrs)
0426 {
0427 int ret;
0428 struct ib_uobject *uobj;
0429
0430 uobj = alloc_uobj(attrs, obj);
0431 if (IS_ERR(uobj))
0432 return uobj;
0433
0434 ret = idr_add_uobj(uobj);
0435 if (ret)
0436 goto uobj_put;
0437
0438 ret = ib_rdmacg_try_charge(&uobj->cg_obj, uobj->context->device,
0439 RDMACG_RESOURCE_HCA_OBJECT);
0440 if (ret)
0441 goto remove;
0442
0443 return uobj;
0444
0445 remove:
0446 xa_erase(&attrs->ufile->idr, uobj->id);
0447 uobj_put:
0448 uverbs_uobject_put(uobj);
0449 return ERR_PTR(ret);
0450 }
0451
0452 static struct ib_uobject *
0453 alloc_begin_fd_uobject(const struct uverbs_api_object *obj,
0454 struct uverbs_attr_bundle *attrs)
0455 {
0456 const struct uverbs_obj_fd_type *fd_type;
0457 int new_fd;
0458 struct ib_uobject *uobj, *ret;
0459 struct file *filp;
0460
0461 uobj = alloc_uobj(attrs, obj);
0462 if (IS_ERR(uobj))
0463 return uobj;
0464
0465 fd_type =
0466 container_of(obj->type_attrs, struct uverbs_obj_fd_type, type);
0467 if (WARN_ON(fd_type->fops->release != &uverbs_uobject_fd_release &&
0468 fd_type->fops->release != &uverbs_async_event_release)) {
0469 ret = ERR_PTR(-EINVAL);
0470 goto err_fd;
0471 }
0472
0473 new_fd = get_unused_fd_flags(O_CLOEXEC);
0474 if (new_fd < 0) {
0475 ret = ERR_PTR(new_fd);
0476 goto err_fd;
0477 }
0478
0479
0480 filp = anon_inode_getfile(fd_type->name, fd_type->fops, NULL,
0481 fd_type->flags);
0482 if (IS_ERR(filp)) {
0483 ret = ERR_CAST(filp);
0484 goto err_getfile;
0485 }
0486 uobj->object = filp;
0487
0488 uobj->id = new_fd;
0489 return uobj;
0490
0491 err_getfile:
0492 put_unused_fd(new_fd);
0493 err_fd:
0494 uverbs_uobject_put(uobj);
0495 return ret;
0496 }
0497
0498 struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj,
0499 struct uverbs_attr_bundle *attrs)
0500 {
0501 struct ib_uverbs_file *ufile = attrs->ufile;
0502 struct ib_uobject *ret;
0503
0504 if (IS_ERR(obj))
0505 return ERR_PTR(-EINVAL);
0506
0507
0508
0509
0510
0511
0512 if (!down_read_trylock(&ufile->hw_destroy_rwsem))
0513 return ERR_PTR(-EIO);
0514
0515 ret = obj->type_class->alloc_begin(obj, attrs);
0516 if (IS_ERR(ret)) {
0517 up_read(&ufile->hw_destroy_rwsem);
0518 return ret;
0519 }
0520 return ret;
0521 }
0522
0523 static void alloc_abort_idr_uobject(struct ib_uobject *uobj)
0524 {
0525 ib_rdmacg_uncharge(&uobj->cg_obj, uobj->context->device,
0526 RDMACG_RESOURCE_HCA_OBJECT);
0527
0528 xa_erase(&uobj->ufile->idr, uobj->id);
0529 }
0530
0531 static int __must_check destroy_hw_idr_uobject(struct ib_uobject *uobj,
0532 enum rdma_remove_reason why,
0533 struct uverbs_attr_bundle *attrs)
0534 {
0535 const struct uverbs_obj_idr_type *idr_type =
0536 container_of(uobj->uapi_object->type_attrs,
0537 struct uverbs_obj_idr_type, type);
0538 int ret = idr_type->destroy_object(uobj, why, attrs);
0539
0540 if (ret)
0541 return ret;
0542
0543 if (why == RDMA_REMOVE_ABORT)
0544 return 0;
0545
0546 ib_rdmacg_uncharge(&uobj->cg_obj, uobj->context->device,
0547 RDMACG_RESOURCE_HCA_OBJECT);
0548
0549 return 0;
0550 }
0551
0552 static void remove_handle_idr_uobject(struct ib_uobject *uobj)
0553 {
0554 xa_erase(&uobj->ufile->idr, uobj->id);
0555
0556 uverbs_uobject_put(uobj);
0557 }
0558
0559 static void alloc_abort_fd_uobject(struct ib_uobject *uobj)
0560 {
0561 struct file *filp = uobj->object;
0562
0563 fput(filp);
0564 put_unused_fd(uobj->id);
0565 }
0566
0567 static int __must_check destroy_hw_fd_uobject(struct ib_uobject *uobj,
0568 enum rdma_remove_reason why,
0569 struct uverbs_attr_bundle *attrs)
0570 {
0571 const struct uverbs_obj_fd_type *fd_type = container_of(
0572 uobj->uapi_object->type_attrs, struct uverbs_obj_fd_type, type);
0573
0574 fd_type->destroy_object(uobj, why);
0575 return 0;
0576 }
0577
0578 static void remove_handle_fd_uobject(struct ib_uobject *uobj)
0579 {
0580 }
0581
0582 static void alloc_commit_idr_uobject(struct ib_uobject *uobj)
0583 {
0584 struct ib_uverbs_file *ufile = uobj->ufile;
0585 void *old;
0586
0587
0588
0589
0590
0591
0592
0593
0594 old = xa_store(&ufile->idr, uobj->id, uobj, GFP_KERNEL);
0595 WARN_ON(old != NULL);
0596 }
0597
0598 static void swap_idr_uobjects(struct ib_uobject *obj_old,
0599 struct ib_uobject *obj_new)
0600 {
0601 struct ib_uverbs_file *ufile = obj_old->ufile;
0602 void *old;
0603
0604
0605
0606
0607
0608 old = xa_cmpxchg(&ufile->idr, obj_old->id, obj_old, XA_ZERO_ENTRY,
0609 GFP_KERNEL);
0610 if (WARN_ON(old != obj_old))
0611 return;
0612
0613 swap(obj_old->id, obj_new->id);
0614
0615 old = xa_cmpxchg(&ufile->idr, obj_old->id, NULL, obj_old, GFP_KERNEL);
0616 WARN_ON(old != NULL);
0617 }
0618
0619 static void alloc_commit_fd_uobject(struct ib_uobject *uobj)
0620 {
0621 int fd = uobj->id;
0622 struct file *filp = uobj->object;
0623
0624
0625 kref_get(&uobj->ufile->ref);
0626
0627
0628 uobj->id = 0;
0629
0630
0631
0632
0633
0634 filp->private_data = uobj;
0635 fd_install(fd, filp);
0636 }
0637
0638
0639
0640
0641
0642
0643 void rdma_alloc_commit_uobject(struct ib_uobject *uobj,
0644 struct uverbs_attr_bundle *attrs)
0645 {
0646 struct ib_uverbs_file *ufile = attrs->ufile;
0647
0648
0649 uverbs_uobject_get(uobj);
0650 spin_lock_irq(&ufile->uobjects_lock);
0651 list_add(&uobj->list, &ufile->uobjects);
0652 spin_unlock_irq(&ufile->uobjects_lock);
0653
0654
0655 atomic_set(&uobj->usecnt, 0);
0656
0657
0658 uobj->uapi_object->type_class->alloc_commit(uobj);
0659
0660
0661 up_read(&ufile->hw_destroy_rwsem);
0662 }
0663
0664
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675 void rdma_assign_uobject(struct ib_uobject *to_uobj, struct ib_uobject *new_uobj,
0676 struct uverbs_attr_bundle *attrs)
0677 {
0678 assert_uverbs_usecnt(new_uobj, UVERBS_LOOKUP_WRITE);
0679
0680 if (WARN_ON(to_uobj->uapi_object != new_uobj->uapi_object ||
0681 !to_uobj->uapi_object->type_class->swap_uobjects))
0682 return;
0683
0684 to_uobj->uapi_object->type_class->swap_uobjects(to_uobj, new_uobj);
0685
0686
0687
0688
0689
0690 uverbs_destroy_uobject(to_uobj, RDMA_REMOVE_DESTROY, attrs);
0691 }
0692
0693
0694
0695
0696
0697 void rdma_alloc_abort_uobject(struct ib_uobject *uobj,
0698 struct uverbs_attr_bundle *attrs,
0699 bool hw_obj_valid)
0700 {
0701 struct ib_uverbs_file *ufile = uobj->ufile;
0702 int ret;
0703
0704 if (hw_obj_valid) {
0705 ret = uobj->uapi_object->type_class->destroy_hw(
0706 uobj, RDMA_REMOVE_ABORT, attrs);
0707
0708
0709
0710
0711
0712
0713 if (WARN_ON(ret))
0714 return rdma_alloc_commit_uobject(uobj, attrs);
0715 }
0716
0717 uverbs_destroy_uobject(uobj, RDMA_REMOVE_ABORT, attrs);
0718
0719
0720 up_read(&ufile->hw_destroy_rwsem);
0721 }
0722
0723 static void lookup_put_idr_uobject(struct ib_uobject *uobj,
0724 enum rdma_lookup_mode mode)
0725 {
0726 }
0727
0728 static void lookup_put_fd_uobject(struct ib_uobject *uobj,
0729 enum rdma_lookup_mode mode)
0730 {
0731 struct file *filp = uobj->object;
0732
0733 WARN_ON(mode != UVERBS_LOOKUP_READ);
0734
0735
0736
0737
0738 fput(filp);
0739 }
0740
0741 void rdma_lookup_put_uobject(struct ib_uobject *uobj,
0742 enum rdma_lookup_mode mode)
0743 {
0744 assert_uverbs_usecnt(uobj, mode);
0745
0746
0747
0748
0749
0750 switch (mode) {
0751 case UVERBS_LOOKUP_READ:
0752 atomic_dec(&uobj->usecnt);
0753 break;
0754 case UVERBS_LOOKUP_WRITE:
0755 atomic_set(&uobj->usecnt, 0);
0756 break;
0757 case UVERBS_LOOKUP_DESTROY:
0758 break;
0759 }
0760
0761 uobj->uapi_object->type_class->lookup_put(uobj, mode);
0762
0763 uverbs_uobject_put(uobj);
0764 }
0765
0766 void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile)
0767 {
0768 xa_init_flags(&ufile->idr, XA_FLAGS_ALLOC);
0769 }
0770
0771 void release_ufile_idr_uobject(struct ib_uverbs_file *ufile)
0772 {
0773 struct ib_uobject *entry;
0774 unsigned long id;
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784 xa_for_each(&ufile->idr, id, entry) {
0785 WARN_ON(entry->object);
0786 uverbs_uobject_put(entry);
0787 }
0788
0789 xa_destroy(&ufile->idr);
0790 }
0791
0792 const struct uverbs_obj_type_class uverbs_idr_class = {
0793 .alloc_begin = alloc_begin_idr_uobject,
0794 .lookup_get = lookup_get_idr_uobject,
0795 .alloc_commit = alloc_commit_idr_uobject,
0796 .alloc_abort = alloc_abort_idr_uobject,
0797 .lookup_put = lookup_put_idr_uobject,
0798 .destroy_hw = destroy_hw_idr_uobject,
0799 .remove_handle = remove_handle_idr_uobject,
0800 .swap_uobjects = swap_idr_uobjects,
0801 };
0802 EXPORT_SYMBOL(uverbs_idr_class);
0803
0804
0805
0806
0807
0808 int uverbs_uobject_fd_release(struct inode *inode, struct file *filp)
0809 {
0810 struct ib_uverbs_file *ufile;
0811 struct ib_uobject *uobj;
0812
0813
0814
0815
0816 if (!filp->private_data)
0817 return 0;
0818 uobj = filp->private_data;
0819 ufile = uobj->ufile;
0820
0821 if (down_read_trylock(&ufile->hw_destroy_rwsem)) {
0822 struct uverbs_attr_bundle attrs = {
0823 .context = uobj->context,
0824 .ufile = ufile,
0825 };
0826
0827
0828
0829
0830
0831
0832
0833 WARN_ON(uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE));
0834 uverbs_destroy_uobject(uobj, RDMA_REMOVE_CLOSE, &attrs);
0835 up_read(&ufile->hw_destroy_rwsem);
0836 }
0837
0838
0839 kref_put(&ufile->ref, ib_uverbs_release_file);
0840
0841
0842 uverbs_uobject_put(uobj);
0843 return 0;
0844 }
0845 EXPORT_SYMBOL(uverbs_uobject_fd_release);
0846
0847
0848
0849
0850
0851 static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile,
0852 enum rdma_remove_reason reason)
0853 {
0854 struct ib_ucontext *ucontext = ufile->ucontext;
0855 struct ib_device *ib_dev = ucontext->device;
0856
0857
0858
0859
0860
0861
0862 if (reason == RDMA_REMOVE_DRIVER_REMOVE) {
0863 uverbs_user_mmap_disassociate(ufile);
0864 if (ib_dev->ops.disassociate_ucontext)
0865 ib_dev->ops.disassociate_ucontext(ucontext);
0866 }
0867
0868 ib_rdmacg_uncharge(&ucontext->cg_obj, ib_dev,
0869 RDMACG_RESOURCE_HCA_HANDLE);
0870
0871 rdma_restrack_del(&ucontext->res);
0872
0873 ib_dev->ops.dealloc_ucontext(ucontext);
0874 WARN_ON(!xa_empty(&ucontext->mmap_xa));
0875 kfree(ucontext);
0876
0877 ufile->ucontext = NULL;
0878 }
0879
0880 static int __uverbs_cleanup_ufile(struct ib_uverbs_file *ufile,
0881 enum rdma_remove_reason reason)
0882 {
0883 struct ib_uobject *obj, *next_obj;
0884 int ret = -EINVAL;
0885 struct uverbs_attr_bundle attrs = { .ufile = ufile };
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896 list_for_each_entry_safe(obj, next_obj, &ufile->uobjects, list) {
0897 attrs.context = obj->context;
0898
0899
0900
0901
0902 WARN_ON(uverbs_try_lock_object(obj, UVERBS_LOOKUP_WRITE));
0903 if (reason == RDMA_REMOVE_DRIVER_FAILURE)
0904 obj->object = NULL;
0905 if (!uverbs_destroy_uobject(obj, reason, &attrs))
0906 ret = 0;
0907 else
0908 atomic_set(&obj->usecnt, 0);
0909 }
0910
0911 if (reason == RDMA_REMOVE_DRIVER_FAILURE) {
0912 WARN_ON(!list_empty(&ufile->uobjects));
0913 return 0;
0914 }
0915 return ret;
0916 }
0917
0918
0919
0920
0921
0922
0923
0924 void uverbs_destroy_ufile_hw(struct ib_uverbs_file *ufile,
0925 enum rdma_remove_reason reason)
0926 {
0927 down_write(&ufile->hw_destroy_rwsem);
0928
0929
0930
0931
0932
0933 if (!ufile->ucontext)
0934 goto done;
0935
0936 while (!list_empty(&ufile->uobjects) &&
0937 !__uverbs_cleanup_ufile(ufile, reason)) {
0938 }
0939
0940 if (WARN_ON(!list_empty(&ufile->uobjects)))
0941 __uverbs_cleanup_ufile(ufile, RDMA_REMOVE_DRIVER_FAILURE);
0942 ufile_destroy_ucontext(ufile, reason);
0943
0944 done:
0945 up_write(&ufile->hw_destroy_rwsem);
0946 }
0947
0948 const struct uverbs_obj_type_class uverbs_fd_class = {
0949 .alloc_begin = alloc_begin_fd_uobject,
0950 .lookup_get = lookup_get_fd_uobject,
0951 .alloc_commit = alloc_commit_fd_uobject,
0952 .alloc_abort = alloc_abort_fd_uobject,
0953 .lookup_put = lookup_put_fd_uobject,
0954 .destroy_hw = destroy_hw_fd_uobject,
0955 .remove_handle = remove_handle_fd_uobject,
0956 };
0957 EXPORT_SYMBOL(uverbs_fd_class);
0958
0959 struct ib_uobject *
0960 uverbs_get_uobject_from_file(u16 object_id, enum uverbs_obj_access access,
0961 s64 id, struct uverbs_attr_bundle *attrs)
0962 {
0963 const struct uverbs_api_object *obj =
0964 uapi_get_object(attrs->ufile->device->uapi, object_id);
0965
0966 switch (access) {
0967 case UVERBS_ACCESS_READ:
0968 return rdma_lookup_get_uobject(obj, attrs->ufile, id,
0969 UVERBS_LOOKUP_READ, attrs);
0970 case UVERBS_ACCESS_DESTROY:
0971
0972 return rdma_lookup_get_uobject(obj, attrs->ufile, id,
0973 UVERBS_LOOKUP_DESTROY, attrs);
0974 case UVERBS_ACCESS_WRITE:
0975 return rdma_lookup_get_uobject(obj, attrs->ufile, id,
0976 UVERBS_LOOKUP_WRITE, attrs);
0977 case UVERBS_ACCESS_NEW:
0978 return rdma_alloc_begin_uobject(obj, attrs);
0979 default:
0980 WARN_ON(true);
0981 return ERR_PTR(-EOPNOTSUPP);
0982 }
0983 }
0984
0985 void uverbs_finalize_object(struct ib_uobject *uobj,
0986 enum uverbs_obj_access access, bool hw_obj_valid,
0987 bool commit, struct uverbs_attr_bundle *attrs)
0988 {
0989
0990
0991
0992
0993
0994
0995 switch (access) {
0996 case UVERBS_ACCESS_READ:
0997 rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_READ);
0998 break;
0999 case UVERBS_ACCESS_WRITE:
1000 rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE);
1001 break;
1002 case UVERBS_ACCESS_DESTROY:
1003 if (uobj)
1004 rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_DESTROY);
1005 break;
1006 case UVERBS_ACCESS_NEW:
1007 if (commit)
1008 rdma_alloc_commit_uobject(uobj, attrs);
1009 else
1010 rdma_alloc_abort_uobject(uobj, attrs, hw_obj_valid);
1011 break;
1012 default:
1013 WARN_ON(true);
1014 }
1015 }