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
42static 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((struct ib_ah *)uobject->object,
47				    RDMA_DESTROY_AH_SLEEPABLE,
48				    &attrs->driver_udata);
49}
50
51static 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(&qp->usecnt);
65		ib_uverbs_flow_resources_free(uflow->resources);
66	}
67
68	return ret;
69}
70
71static 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((struct ib_mw *)uobject->object);
76}
77
78static 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(&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(&ind_tbl[i]->usecnt);
96
97	kfree(rwq_ind_tbl);
98	kfree(ind_tbl);
99	return 0;
100}
101
102static 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(&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(&attrs->ufile->device->xrcd_tree_mutex);
117
118	return ret;
119}
120
121static 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(&pd->usecnt))
128		return -EBUSY;
129
130	return ib_dealloc_pd_user(pd, &attrs->driver_udata);
131}
132
133void 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(&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(&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(&event_queue->lock);
148	list_for_each_entry_safe(entry, tmp, &event_queue->event_list, list) {
149		if (entry->counter)
150			list_del(&entry->obj_list);
151		list_del(&entry->list);
152		kfree(entry);
153	}
154	spin_unlock_irq(&event_queue->lock);
155}
156
157static void
158uverbs_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(&file->ev_queue);
166}
167
168int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs)
169{
170	return 0;
171}
172EXPORT_SYMBOL(uverbs_destroy_def_handler);
173
174DECLARE_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
182DECLARE_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
189DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_MW,
190			    UVERBS_TYPE_ALLOC_IDR(uverbs_free_mw),
191			    &UVERBS_METHOD(UVERBS_METHOD_MW_DESTROY));
192
193DECLARE_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
200DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_AH,
201			    UVERBS_TYPE_ALLOC_IDR(uverbs_free_ah),
202			    &UVERBS_METHOD(UVERBS_METHOD_AH_DESTROY));
203
204DECLARE_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
211DECLARE_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
217DECLARE_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
224DECLARE_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
228DECLARE_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
235DECLARE_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
241DECLARE_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
248DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_PD,
249			    UVERBS_TYPE_ALLOC_IDR(uverbs_free_pd),
250			    &UVERBS_METHOD(UVERBS_METHOD_PD_DESTROY));
251
252const 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