1 | /* |
2 | * Copyright (c) 2017, 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 <rdma/uverbs_std_types.h> |
34 | #include <rdma/ib_user_verbs.h> |
35 | #include <rdma/ib_verbs.h> |
36 | #include <linux/bug.h> |
37 | #include <linux/file.h> |
38 | #include <rdma/restrack.h> |
39 | #include "rdma_core.h" |
40 | #include "uverbs.h" |
41 | |
42 | static int uverbs_free_ah(struct ib_uobject *uobject, |
43 | enum rdma_remove_reason why, |
44 | struct uverbs_attr_bundle *attrs) |
45 | { |
46 | return rdma_destroy_ah_user(ah: (struct ib_ah *)uobject->object, |
47 | flags: RDMA_DESTROY_AH_SLEEPABLE, |
48 | udata: &attrs->driver_udata); |
49 | } |
50 | |
51 | static int uverbs_free_flow(struct ib_uobject *uobject, |
52 | enum rdma_remove_reason why, |
53 | struct uverbs_attr_bundle *attrs) |
54 | { |
55 | struct ib_flow *flow = (struct ib_flow *)uobject->object; |
56 | struct ib_uflow_object *uflow = |
57 | container_of(uobject, struct ib_uflow_object, uobject); |
58 | struct ib_qp *qp = flow->qp; |
59 | int ret; |
60 | |
61 | ret = flow->device->ops.destroy_flow(flow); |
62 | if (!ret) { |
63 | if (qp) |
64 | atomic_dec(v: &qp->usecnt); |
65 | ib_uverbs_flow_resources_free(uflow_res: uflow->resources); |
66 | } |
67 | |
68 | return ret; |
69 | } |
70 | |
71 | static int uverbs_free_mw(struct ib_uobject *uobject, |
72 | enum rdma_remove_reason why, |
73 | struct uverbs_attr_bundle *attrs) |
74 | { |
75 | return uverbs_dealloc_mw(mw: (struct ib_mw *)uobject->object); |
76 | } |
77 | |
78 | static int uverbs_free_rwq_ind_tbl(struct ib_uobject *uobject, |
79 | enum rdma_remove_reason why, |
80 | struct uverbs_attr_bundle *attrs) |
81 | { |
82 | struct ib_rwq_ind_table *rwq_ind_tbl = uobject->object; |
83 | struct ib_wq **ind_tbl = rwq_ind_tbl->ind_tbl; |
84 | u32 table_size = (1 << rwq_ind_tbl->log_ind_tbl_size); |
85 | int ret, i; |
86 | |
87 | if (atomic_read(v: &rwq_ind_tbl->usecnt)) |
88 | return -EBUSY; |
89 | |
90 | ret = rwq_ind_tbl->device->ops.destroy_rwq_ind_table(rwq_ind_tbl); |
91 | if (ret) |
92 | return ret; |
93 | |
94 | for (i = 0; i < table_size; i++) |
95 | atomic_dec(v: &ind_tbl[i]->usecnt); |
96 | |
97 | kfree(objp: rwq_ind_tbl); |
98 | kfree(objp: ind_tbl); |
99 | return 0; |
100 | } |
101 | |
102 | static int uverbs_free_xrcd(struct ib_uobject *uobject, |
103 | enum rdma_remove_reason why, |
104 | struct uverbs_attr_bundle *attrs) |
105 | { |
106 | struct ib_xrcd *xrcd = uobject->object; |
107 | struct ib_uxrcd_object *uxrcd = |
108 | container_of(uobject, struct ib_uxrcd_object, uobject); |
109 | int ret; |
110 | |
111 | if (atomic_read(v: &uxrcd->refcnt)) |
112 | return -EBUSY; |
113 | |
114 | mutex_lock(&attrs->ufile->device->xrcd_tree_mutex); |
115 | ret = ib_uverbs_dealloc_xrcd(uobject, xrcd, why, attrs); |
116 | mutex_unlock(lock: &attrs->ufile->device->xrcd_tree_mutex); |
117 | |
118 | return ret; |
119 | } |
120 | |
121 | static int uverbs_free_pd(struct ib_uobject *uobject, |
122 | enum rdma_remove_reason why, |
123 | struct uverbs_attr_bundle *attrs) |
124 | { |
125 | struct ib_pd *pd = uobject->object; |
126 | |
127 | if (atomic_read(v: &pd->usecnt)) |
128 | return -EBUSY; |
129 | |
130 | return ib_dealloc_pd_user(pd, udata: &attrs->driver_udata); |
131 | } |
132 | |
133 | void ib_uverbs_free_event_queue(struct ib_uverbs_event_queue *event_queue) |
134 | { |
135 | struct ib_uverbs_event *entry, *tmp; |
136 | |
137 | spin_lock_irq(lock: &event_queue->lock); |
138 | /* |
139 | * The user must ensure that no new items are added to the event_list |
140 | * once is_closed is set. |
141 | */ |
142 | event_queue->is_closed = 1; |
143 | spin_unlock_irq(lock: &event_queue->lock); |
144 | wake_up_interruptible(&event_queue->poll_wait); |
145 | kill_fasync(&event_queue->async_queue, SIGIO, POLL_IN); |
146 | |
147 | spin_lock_irq(lock: &event_queue->lock); |
148 | list_for_each_entry_safe(entry, tmp, &event_queue->event_list, list) { |
149 | if (entry->counter) |
150 | list_del(entry: &entry->obj_list); |
151 | list_del(entry: &entry->list); |
152 | kfree(objp: entry); |
153 | } |
154 | spin_unlock_irq(lock: &event_queue->lock); |
155 | } |
156 | |
157 | static void |
158 | uverbs_completion_event_file_destroy_uobj(struct ib_uobject *uobj, |
159 | enum rdma_remove_reason why) |
160 | { |
161 | struct ib_uverbs_completion_event_file *file = |
162 | container_of(uobj, struct ib_uverbs_completion_event_file, |
163 | uobj); |
164 | |
165 | ib_uverbs_free_event_queue(event_queue: &file->ev_queue); |
166 | } |
167 | |
168 | int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs) |
169 | { |
170 | return 0; |
171 | } |
172 | EXPORT_SYMBOL(uverbs_destroy_def_handler); |
173 | |
174 | DECLARE_UVERBS_NAMED_OBJECT( |
175 | UVERBS_OBJECT_COMP_CHANNEL, |
176 | UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_completion_event_file), |
177 | uverbs_completion_event_file_destroy_uobj, |
178 | &uverbs_event_fops, |
179 | "[infinibandevent]" , |
180 | O_RDONLY)); |
181 | |
182 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
183 | UVERBS_METHOD_MW_DESTROY, |
184 | UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_MW_HANDLE, |
185 | UVERBS_OBJECT_MW, |
186 | UVERBS_ACCESS_DESTROY, |
187 | UA_MANDATORY)); |
188 | |
189 | DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_MW, |
190 | UVERBS_TYPE_ALLOC_IDR(uverbs_free_mw), |
191 | &UVERBS_METHOD(UVERBS_METHOD_MW_DESTROY)); |
192 | |
193 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
194 | UVERBS_METHOD_AH_DESTROY, |
195 | UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_AH_HANDLE, |
196 | UVERBS_OBJECT_AH, |
197 | UVERBS_ACCESS_DESTROY, |
198 | UA_MANDATORY)); |
199 | |
200 | DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_AH, |
201 | UVERBS_TYPE_ALLOC_IDR(uverbs_free_ah), |
202 | &UVERBS_METHOD(UVERBS_METHOD_AH_DESTROY)); |
203 | |
204 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
205 | UVERBS_METHOD_FLOW_DESTROY, |
206 | UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_FLOW_HANDLE, |
207 | UVERBS_OBJECT_FLOW, |
208 | UVERBS_ACCESS_DESTROY, |
209 | UA_MANDATORY)); |
210 | |
211 | DECLARE_UVERBS_NAMED_OBJECT( |
212 | UVERBS_OBJECT_FLOW, |
213 | UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uflow_object), |
214 | uverbs_free_flow), |
215 | &UVERBS_METHOD(UVERBS_METHOD_FLOW_DESTROY)); |
216 | |
217 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
218 | UVERBS_METHOD_RWQ_IND_TBL_DESTROY, |
219 | UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_RWQ_IND_TBL_HANDLE, |
220 | UVERBS_OBJECT_RWQ_IND_TBL, |
221 | UVERBS_ACCESS_DESTROY, |
222 | UA_MANDATORY)); |
223 | |
224 | DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_RWQ_IND_TBL, |
225 | UVERBS_TYPE_ALLOC_IDR(uverbs_free_rwq_ind_tbl), |
226 | &UVERBS_METHOD(UVERBS_METHOD_RWQ_IND_TBL_DESTROY)); |
227 | |
228 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
229 | UVERBS_METHOD_XRCD_DESTROY, |
230 | UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_XRCD_HANDLE, |
231 | UVERBS_OBJECT_XRCD, |
232 | UVERBS_ACCESS_DESTROY, |
233 | UA_MANDATORY)); |
234 | |
235 | DECLARE_UVERBS_NAMED_OBJECT( |
236 | UVERBS_OBJECT_XRCD, |
237 | UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uxrcd_object), |
238 | uverbs_free_xrcd), |
239 | &UVERBS_METHOD(UVERBS_METHOD_XRCD_DESTROY)); |
240 | |
241 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
242 | UVERBS_METHOD_PD_DESTROY, |
243 | UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_PD_HANDLE, |
244 | UVERBS_OBJECT_PD, |
245 | UVERBS_ACCESS_DESTROY, |
246 | UA_MANDATORY)); |
247 | |
248 | DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_PD, |
249 | UVERBS_TYPE_ALLOC_IDR(uverbs_free_pd), |
250 | &UVERBS_METHOD(UVERBS_METHOD_PD_DESTROY)); |
251 | |
252 | const struct uapi_definition uverbs_def_obj_intf[] = { |
253 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_PD, |
254 | UAPI_DEF_OBJ_NEEDS_FN(dealloc_pd)), |
255 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CHANNEL, |
256 | UAPI_DEF_OBJ_NEEDS_FN(dealloc_pd)), |
257 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_AH, |
258 | UAPI_DEF_OBJ_NEEDS_FN(destroy_ah)), |
259 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_MW, |
260 | UAPI_DEF_OBJ_NEEDS_FN(dealloc_mw)), |
261 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_FLOW, |
262 | UAPI_DEF_OBJ_NEEDS_FN(destroy_flow)), |
263 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED( |
264 | UVERBS_OBJECT_RWQ_IND_TBL, |
265 | UAPI_DEF_OBJ_NEEDS_FN(destroy_rwq_ind_table)), |
266 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_XRCD, |
267 | UAPI_DEF_OBJ_NEEDS_FN(dealloc_xrcd)), |
268 | {} |
269 | }; |
270 | |