| 1 | /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ |
| 2 | /* |
| 3 | * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. |
| 4 | */ |
| 5 | |
| 6 | #ifndef _UVERBS_TYPES_ |
| 7 | #define _UVERBS_TYPES_ |
| 8 | |
| 9 | #include <linux/kernel.h> |
| 10 | #include <rdma/ib_verbs.h> |
| 11 | |
| 12 | struct uverbs_obj_type; |
| 13 | struct uverbs_api_object; |
| 14 | |
| 15 | enum rdma_lookup_mode { |
| 16 | UVERBS_LOOKUP_READ, |
| 17 | UVERBS_LOOKUP_WRITE, |
| 18 | /* |
| 19 | * Destroy is like LOOKUP_WRITE, except that the uobject is not |
| 20 | * locked. uobj_destroy is used to convert a LOOKUP_DESTROY lock into |
| 21 | * a LOOKUP_WRITE lock. |
| 22 | */ |
| 23 | UVERBS_LOOKUP_DESTROY, |
| 24 | }; |
| 25 | |
| 26 | /* |
| 27 | * The following sequences are valid: |
| 28 | * Success flow: |
| 29 | * alloc_begin |
| 30 | * alloc_commit |
| 31 | * [..] |
| 32 | * Access flow: |
| 33 | * lookup_get(exclusive=false) & uverbs_try_lock_object |
| 34 | * lookup_put(exclusive=false) via rdma_lookup_put_uobject |
| 35 | * Destruction flow: |
| 36 | * lookup_get(exclusive=true) & uverbs_try_lock_object |
| 37 | * remove_commit |
| 38 | * remove_handle (optional) |
| 39 | * lookup_put(exclusive=true) via rdma_lookup_put_uobject |
| 40 | * |
| 41 | * Allocate Error flow #1 |
| 42 | * alloc_begin |
| 43 | * alloc_abort |
| 44 | * Allocate Error flow #2 |
| 45 | * alloc_begin |
| 46 | * remove_commit |
| 47 | * alloc_abort |
| 48 | * Allocate Error flow #3 |
| 49 | * alloc_begin |
| 50 | * alloc_commit (fails) |
| 51 | * remove_commit |
| 52 | * alloc_abort |
| 53 | * |
| 54 | * In all cases the caller must hold the ufile kref until alloc_commit or |
| 55 | * alloc_abort returns. |
| 56 | */ |
| 57 | struct uverbs_obj_type_class { |
| 58 | struct ib_uobject *(*alloc_begin)(const struct uverbs_api_object *obj, |
| 59 | struct uverbs_attr_bundle *attrs); |
| 60 | /* This consumes the kref on uobj */ |
| 61 | void (*alloc_commit)(struct ib_uobject *uobj); |
| 62 | /* This does not consume the kref on uobj */ |
| 63 | void (*alloc_abort)(struct ib_uobject *uobj); |
| 64 | |
| 65 | struct ib_uobject *(*lookup_get)(const struct uverbs_api_object *obj, |
| 66 | struct ib_uverbs_file *ufile, s64 id, |
| 67 | enum rdma_lookup_mode mode); |
| 68 | void (*lookup_put)(struct ib_uobject *uobj, enum rdma_lookup_mode mode); |
| 69 | /* This does not consume the kref on uobj */ |
| 70 | int __must_check (*destroy_hw)(struct ib_uobject *uobj, |
| 71 | enum rdma_remove_reason why, |
| 72 | struct uverbs_attr_bundle *attrs); |
| 73 | void (*remove_handle)(struct ib_uobject *uobj); |
| 74 | void (*swap_uobjects)(struct ib_uobject *obj_old, |
| 75 | struct ib_uobject *obj_new); |
| 76 | }; |
| 77 | |
| 78 | struct uverbs_obj_type { |
| 79 | const struct uverbs_obj_type_class * const type_class; |
| 80 | size_t obj_size; |
| 81 | }; |
| 82 | |
| 83 | /* |
| 84 | * Objects type classes which support a detach state (object is still alive but |
| 85 | * it's not attached to any context need to make sure: |
| 86 | * (a) no call through to a driver after a detach is called |
| 87 | * (b) detach isn't called concurrently with context_cleanup |
| 88 | */ |
| 89 | |
| 90 | struct uverbs_obj_idr_type { |
| 91 | /* |
| 92 | * In idr based objects, uverbs_obj_type_class points to a generic |
| 93 | * idr operations. In order to specialize the underlying types (e.g. CQ, |
| 94 | * QPs, etc.), we add destroy_object specific callbacks. |
| 95 | */ |
| 96 | struct uverbs_obj_type type; |
| 97 | |
| 98 | /* Free driver resources from the uobject, make the driver uncallable, |
| 99 | * and move the uobject to the detached state. If the object was |
| 100 | * destroyed by the user's request, a failure should leave the uobject |
| 101 | * completely unchanged. |
| 102 | */ |
| 103 | int __must_check (*destroy_object)(struct ib_uobject *uobj, |
| 104 | enum rdma_remove_reason why, |
| 105 | struct uverbs_attr_bundle *attrs); |
| 106 | }; |
| 107 | |
| 108 | struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_api_object *obj, |
| 109 | struct ib_uverbs_file *ufile, s64 id, |
| 110 | enum rdma_lookup_mode mode, |
| 111 | struct uverbs_attr_bundle *attrs); |
| 112 | void rdma_lookup_put_uobject(struct ib_uobject *uobj, |
| 113 | enum rdma_lookup_mode mode); |
| 114 | struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_api_object *obj, |
| 115 | struct uverbs_attr_bundle *attrs); |
| 116 | void rdma_alloc_abort_uobject(struct ib_uobject *uobj, |
| 117 | struct uverbs_attr_bundle *attrs, |
| 118 | bool hw_obj_valid); |
| 119 | void rdma_alloc_commit_uobject(struct ib_uobject *uobj, |
| 120 | struct uverbs_attr_bundle *attrs); |
| 121 | void rdma_assign_uobject(struct ib_uobject *to_uobj, |
| 122 | struct ib_uobject *new_uobj, |
| 123 | struct uverbs_attr_bundle *attrs); |
| 124 | |
| 125 | /* |
| 126 | * uverbs_uobject_get is called in order to increase the reference count on |
| 127 | * an uobject. This is useful when a handler wants to keep the uobject's memory |
| 128 | * alive, regardless if this uobject is still alive in the context's objects |
| 129 | * repository. Objects are put via uverbs_uobject_put. |
| 130 | */ |
| 131 | static inline void uverbs_uobject_get(struct ib_uobject *uobject) |
| 132 | { |
| 133 | kref_get(kref: &uobject->ref); |
| 134 | } |
| 135 | void uverbs_uobject_put(struct ib_uobject *uobject); |
| 136 | |
| 137 | int uverbs_try_lock_object(struct ib_uobject *uobj, enum rdma_lookup_mode mode); |
| 138 | |
| 139 | struct uverbs_obj_fd_type { |
| 140 | /* |
| 141 | * In fd based objects, uverbs_obj_type_ops points to generic |
| 142 | * fd operations. In order to specialize the underlying types (e.g. |
| 143 | * completion_channel), we use fops, name and flags for fd creation. |
| 144 | * destroy_object is called when the uobject is to be destroyed, |
| 145 | * because the driver is removed or the FD is closed. |
| 146 | */ |
| 147 | struct uverbs_obj_type type; |
| 148 | void (*destroy_object)(struct ib_uobject *uobj, |
| 149 | enum rdma_remove_reason why); |
| 150 | const struct file_operations *fops; |
| 151 | const char *name; |
| 152 | int flags; |
| 153 | }; |
| 154 | |
| 155 | struct ib_uverbs_file { |
| 156 | struct kref ref; |
| 157 | struct ib_uverbs_device *device; |
| 158 | struct mutex ucontext_lock; |
| 159 | /* |
| 160 | * ucontext must be accessed via ib_uverbs_get_ucontext() or with |
| 161 | * ucontext_lock held |
| 162 | */ |
| 163 | struct ib_ucontext *ucontext; |
| 164 | struct ib_uverbs_async_event_file *default_async_file; |
| 165 | struct list_head list; |
| 166 | |
| 167 | /* |
| 168 | * To access the uobjects list hw_destroy_rwsem must be held for write |
| 169 | * OR hw_destroy_rwsem held for read AND uobjects_lock held. |
| 170 | * hw_destroy_rwsem should be called across any destruction of the HW |
| 171 | * object of an associated uobject. |
| 172 | */ |
| 173 | struct rw_semaphore hw_destroy_rwsem; |
| 174 | spinlock_t uobjects_lock; |
| 175 | struct list_head uobjects; |
| 176 | |
| 177 | struct mutex umap_lock; |
| 178 | struct list_head umaps; |
| 179 | struct page *disassociate_page; |
| 180 | |
| 181 | struct xarray idr; |
| 182 | |
| 183 | struct mutex disassociation_lock; |
| 184 | }; |
| 185 | |
| 186 | extern const struct uverbs_obj_type_class uverbs_idr_class; |
| 187 | extern const struct uverbs_obj_type_class uverbs_fd_class; |
| 188 | int uverbs_uobject_fd_release(struct inode *inode, struct file *filp); |
| 189 | |
| 190 | #define UVERBS_BUILD_BUG_ON(cond) (sizeof(char[1 - 2 * !!(cond)]) - \ |
| 191 | sizeof(char)) |
| 192 | #define UVERBS_TYPE_ALLOC_FD(_obj_size, _destroy_object, _fops, _name, _flags) \ |
| 193 | ((&((const struct uverbs_obj_fd_type) \ |
| 194 | {.type = { \ |
| 195 | .type_class = &uverbs_fd_class, \ |
| 196 | .obj_size = (_obj_size) + \ |
| 197 | UVERBS_BUILD_BUG_ON((_obj_size) < \ |
| 198 | sizeof(struct ib_uobject)), \ |
| 199 | }, \ |
| 200 | .destroy_object = _destroy_object, \ |
| 201 | .fops = _fops, \ |
| 202 | .name = _name, \ |
| 203 | .flags = _flags}))->type) |
| 204 | #define UVERBS_TYPE_ALLOC_IDR_SZ(_size, _destroy_object) \ |
| 205 | ((&((const struct uverbs_obj_idr_type) \ |
| 206 | {.type = { \ |
| 207 | .type_class = &uverbs_idr_class, \ |
| 208 | .obj_size = (_size) + \ |
| 209 | UVERBS_BUILD_BUG_ON((_size) < \ |
| 210 | sizeof(struct ib_uobject)) \ |
| 211 | }, \ |
| 212 | .destroy_object = _destroy_object,}))->type) |
| 213 | #define UVERBS_TYPE_ALLOC_IDR(_destroy_object) \ |
| 214 | UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uobject), \ |
| 215 | _destroy_object) |
| 216 | |
| 217 | #endif |
| 218 | |