]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/infiniband/core/uverbs_uapi.c
x86/intel_rdt: Show missing resctrl mount options
[linux.git] / drivers / infiniband / core / uverbs_uapi.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3  * Copyright (c) 2017, Mellanox Technologies inc.  All rights reserved.
4  */
5 #include <rdma/uverbs_ioctl.h>
6 #include <rdma/rdma_user_ioctl.h>
7 #include <linux/bitops.h>
8 #include "rdma_core.h"
9 #include "uverbs.h"
10
11 static void *uapi_add_elm(struct uverbs_api *uapi, u32 key, size_t alloc_size)
12 {
13         void *elm;
14         int rc;
15
16         if (key == UVERBS_API_KEY_ERR)
17                 return ERR_PTR(-EOVERFLOW);
18
19         elm = kzalloc(alloc_size, GFP_KERNEL);
20         rc = radix_tree_insert(&uapi->radix, key, elm);
21         if (rc) {
22                 kfree(elm);
23                 return ERR_PTR(rc);
24         }
25
26         return elm;
27 }
28
29 static int uapi_merge_method(struct uverbs_api *uapi,
30                              struct uverbs_api_object *obj_elm, u32 obj_key,
31                              const struct uverbs_method_def *method,
32                              bool is_driver)
33 {
34         u32 method_key = obj_key | uapi_key_ioctl_method(method->id);
35         struct uverbs_api_ioctl_method *method_elm;
36         unsigned int i;
37
38         if (!method->attrs)
39                 return 0;
40
41         method_elm = uapi_add_elm(uapi, method_key, sizeof(*method_elm));
42         if (IS_ERR(method_elm)) {
43                 if (method_elm != ERR_PTR(-EEXIST))
44                         return PTR_ERR(method_elm);
45
46                 /*
47                  * This occurs when a driver uses ADD_UVERBS_ATTRIBUTES_SIMPLE
48                  */
49                 if (WARN_ON(method->handler))
50                         return -EINVAL;
51                 method_elm = radix_tree_lookup(&uapi->radix, method_key);
52                 if (WARN_ON(!method_elm))
53                         return -EINVAL;
54         } else {
55                 WARN_ON(!method->handler);
56                 rcu_assign_pointer(method_elm->handler, method->handler);
57                 if (method->handler != uverbs_destroy_def_handler)
58                         method_elm->driver_method = is_driver;
59         }
60
61         for (i = 0; i != method->num_attrs; i++) {
62                 const struct uverbs_attr_def *attr = (*method->attrs)[i];
63                 struct uverbs_api_attr *attr_slot;
64
65                 if (!attr)
66                         continue;
67
68                 /*
69                  * ENUM_IN contains the 'ids' pointer to the driver's .rodata,
70                  * so if it is specified by a driver then it always makes this
71                  * into a driver method.
72                  */
73                 if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN)
74                         method_elm->driver_method |= is_driver;
75
76                 attr_slot =
77                         uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id),
78                                      sizeof(*attr_slot));
79                 /* Attributes are not allowed to be modified by drivers */
80                 if (IS_ERR(attr_slot))
81                         return PTR_ERR(attr_slot);
82
83                 attr_slot->spec = attr->attr;
84         }
85
86         return 0;
87 }
88
89 static int uapi_merge_tree(struct uverbs_api *uapi,
90                            const struct uverbs_object_tree_def *tree,
91                            bool is_driver)
92 {
93         unsigned int i, j;
94         int rc;
95
96         if (!tree->objects)
97                 return 0;
98
99         for (i = 0; i != tree->num_objects; i++) {
100                 const struct uverbs_object_def *obj = (*tree->objects)[i];
101                 struct uverbs_api_object *obj_elm;
102                 u32 obj_key;
103
104                 if (!obj)
105                         continue;
106
107                 obj_key = uapi_key_obj(obj->id);
108                 obj_elm = uapi_add_elm(uapi, obj_key, sizeof(*obj_elm));
109                 if (IS_ERR(obj_elm)) {
110                         if (obj_elm != ERR_PTR(-EEXIST))
111                                 return PTR_ERR(obj_elm);
112
113                         /* This occurs when a driver uses ADD_UVERBS_METHODS */
114                         if (WARN_ON(obj->type_attrs))
115                                 return -EINVAL;
116                         obj_elm = radix_tree_lookup(&uapi->radix, obj_key);
117                         if (WARN_ON(!obj_elm))
118                                 return -EINVAL;
119                 } else {
120                         obj_elm->type_attrs = obj->type_attrs;
121                         if (obj->type_attrs) {
122                                 obj_elm->type_class =
123                                         obj->type_attrs->type_class;
124                                 /*
125                                  * Today drivers are only permitted to use
126                                  * idr_class types. They cannot use FD types
127                                  * because we currently have no way to revoke
128                                  * the fops pointer after device
129                                  * disassociation.
130                                  */
131                                 if (WARN_ON(is_driver &&
132                                             obj->type_attrs->type_class !=
133                                                     &uverbs_idr_class))
134                                         return -EINVAL;
135                         }
136                 }
137
138                 if (!obj->methods)
139                         continue;
140
141                 for (j = 0; j != obj->num_methods; j++) {
142                         const struct uverbs_method_def *method =
143                                 (*obj->methods)[j];
144                         if (!method)
145                                 continue;
146
147                         rc = uapi_merge_method(uapi, obj_elm, obj_key, method,
148                                                is_driver);
149                         if (rc)
150                                 return rc;
151                 }
152         }
153
154         return 0;
155 }
156
157 static int
158 uapi_finalize_ioctl_method(struct uverbs_api *uapi,
159                            struct uverbs_api_ioctl_method *method_elm,
160                            u32 method_key)
161 {
162         struct radix_tree_iter iter;
163         unsigned int num_attrs = 0;
164         unsigned int max_bkey = 0;
165         bool single_uobj = false;
166         void __rcu **slot;
167
168         method_elm->destroy_bkey = UVERBS_API_ATTR_BKEY_LEN;
169         radix_tree_for_each_slot (slot, &uapi->radix, &iter,
170                                   uapi_key_attrs_start(method_key)) {
171                 struct uverbs_api_attr *elm =
172                         rcu_dereference_protected(*slot, true);
173                 u32 attr_key = iter.index & UVERBS_API_ATTR_KEY_MASK;
174                 u32 attr_bkey = uapi_bkey_attr(attr_key);
175                 u8 type = elm->spec.type;
176
177                 if (uapi_key_attr_to_method(iter.index) !=
178                     uapi_key_attr_to_method(method_key))
179                         break;
180
181                 if (elm->spec.mandatory)
182                         __set_bit(attr_bkey, method_elm->attr_mandatory);
183
184                 if (type == UVERBS_ATTR_TYPE_IDR ||
185                     type == UVERBS_ATTR_TYPE_FD) {
186                         u8 access = elm->spec.u.obj.access;
187
188                         /*
189                          * Verbs specs may only have one NEW/DESTROY, we don't
190                          * have the infrastructure to abort multiple NEW's or
191                          * cope with multiple DESTROY failure.
192                          */
193                         if (access == UVERBS_ACCESS_NEW ||
194                             access == UVERBS_ACCESS_DESTROY) {
195                                 if (WARN_ON(single_uobj))
196                                         return -EINVAL;
197
198                                 single_uobj = true;
199                                 if (WARN_ON(!elm->spec.mandatory))
200                                         return -EINVAL;
201                         }
202
203                         if (access == UVERBS_ACCESS_DESTROY)
204                                 method_elm->destroy_bkey = attr_bkey;
205                 }
206
207                 max_bkey = max(max_bkey, attr_bkey);
208                 num_attrs++;
209         }
210
211         method_elm->key_bitmap_len = max_bkey + 1;
212         WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN);
213
214         uapi_compute_bundle_size(method_elm, num_attrs);
215         return 0;
216 }
217
218 static int uapi_finalize(struct uverbs_api *uapi)
219 {
220         struct radix_tree_iter iter;
221         void __rcu **slot;
222         int rc;
223
224         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
225                 struct uverbs_api_ioctl_method *method_elm =
226                         rcu_dereference_protected(*slot, true);
227
228                 if (uapi_key_is_ioctl_method(iter.index)) {
229                         rc = uapi_finalize_ioctl_method(uapi, method_elm,
230                                                         iter.index);
231                         if (rc)
232                                 return rc;
233                 }
234         }
235
236         return 0;
237 }
238
239 void uverbs_destroy_api(struct uverbs_api *uapi)
240 {
241         struct radix_tree_iter iter;
242         void __rcu **slot;
243
244         if (!uapi)
245                 return;
246
247         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
248                 kfree(rcu_dereference_protected(*slot, true));
249                 radix_tree_iter_delete(&uapi->radix, &iter, slot);
250         }
251 }
252
253 struct uverbs_api *uverbs_alloc_api(
254         const struct uverbs_object_tree_def *const *driver_specs,
255         enum rdma_driver_id driver_id)
256 {
257         struct uverbs_api *uapi;
258         int rc;
259
260         uapi = kzalloc(sizeof(*uapi), GFP_KERNEL);
261         if (!uapi)
262                 return ERR_PTR(-ENOMEM);
263
264         INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL);
265         uapi->driver_id = driver_id;
266
267         rc = uapi_merge_tree(uapi, uverbs_default_get_objects(), false);
268         if (rc)
269                 goto err;
270
271         for (; driver_specs && *driver_specs; driver_specs++) {
272                 rc = uapi_merge_tree(uapi, *driver_specs, true);
273                 if (rc)
274                         goto err;
275         }
276
277         rc = uapi_finalize(uapi);
278         if (rc)
279                 goto err;
280
281         return uapi;
282 err:
283         if (rc != -ENOMEM)
284                 pr_err("Setup of uverbs_api failed, kernel parsing tree description is not valid (%d)??\n",
285                        rc);
286
287         uverbs_destroy_api(uapi);
288         return ERR_PTR(rc);
289 }
290
291 /*
292  * The pre version is done before destroying the HW objects, it only blocks
293  * off method access. All methods that require the ib_dev or the module data
294  * must test one of these assignments prior to continuing.
295  */
296 void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev)
297 {
298         struct uverbs_api *uapi = uverbs_dev->uapi;
299         struct radix_tree_iter iter;
300         void __rcu **slot;
301
302         rcu_assign_pointer(uverbs_dev->ib_dev, NULL);
303
304         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
305                 if (uapi_key_is_ioctl_method(iter.index)) {
306                         struct uverbs_api_ioctl_method *method_elm =
307                                 rcu_dereference_protected(*slot, true);
308
309                         if (method_elm->driver_method)
310                                 rcu_assign_pointer(method_elm->handler, NULL);
311                 }
312         }
313
314         synchronize_srcu(&uverbs_dev->disassociate_srcu);
315 }
316
317 /*
318  * Called when a driver disassociates from the ib_uverbs_device. The
319  * assumption is that the driver module will unload after. Replace everything
320  * related to the driver with NULL as a safety measure.
321  */
322 void uverbs_disassociate_api(struct uverbs_api *uapi)
323 {
324         struct radix_tree_iter iter;
325         void __rcu **slot;
326
327         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
328                 if (uapi_key_is_object(iter.index)) {
329                         struct uverbs_api_object *object_elm =
330                                 rcu_dereference_protected(*slot, true);
331
332                         /*
333                          * Some type_attrs are in the driver module. We don't
334                          * bother to keep track of which since there should be
335                          * no use of this after disassociate.
336                          */
337                         object_elm->type_attrs = NULL;
338                 } else if (uapi_key_is_attr(iter.index)) {
339                         struct uverbs_api_attr *elm =
340                                 rcu_dereference_protected(*slot, true);
341
342                         if (elm->spec.type == UVERBS_ATTR_TYPE_ENUM_IN)
343                                 elm->spec.u2.enum_def.ids = NULL;
344                 }
345         }
346 }