]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/infiniband/core/uverbs_uapi.c
4870c9c1608478a42a3875f03e6b82ca0a0538a2
[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 int ib_uverbs_notsupp(struct uverbs_attr_bundle *attrs,
12                              const char __user *buf, int in_len, int out_len)
13 {
14         return -EOPNOTSUPP;
15 }
16
17 static int ib_uverbs_ex_notsupp(struct uverbs_attr_bundle *attrs,
18                                 struct ib_udata *ucore, struct ib_udata *uhw)
19 {
20         return -EOPNOTSUPP;
21 }
22
23 static void *uapi_add_elm(struct uverbs_api *uapi, u32 key, size_t alloc_size)
24 {
25         void *elm;
26         int rc;
27
28         if (key == UVERBS_API_KEY_ERR)
29                 return ERR_PTR(-EOVERFLOW);
30
31         elm = kzalloc(alloc_size, GFP_KERNEL);
32         rc = radix_tree_insert(&uapi->radix, key, elm);
33         if (rc) {
34                 kfree(elm);
35                 return ERR_PTR(rc);
36         }
37
38         return elm;
39 }
40
41 static void *uapi_add_get_elm(struct uverbs_api *uapi, u32 key,
42                               size_t alloc_size, bool *exists)
43 {
44         void *elm;
45
46         elm = uapi_add_elm(uapi, key, alloc_size);
47         if (!IS_ERR(elm)) {
48                 *exists = false;
49                 return elm;
50         }
51
52         if (elm != ERR_PTR(-EEXIST))
53                 return elm;
54
55         elm = radix_tree_lookup(&uapi->radix, key);
56         if (WARN_ON(!elm))
57                 return ERR_PTR(-EINVAL);
58         *exists = true;
59         return elm;
60 }
61
62 static int uapi_create_write(struct uverbs_api *uapi,
63                              struct ib_device *ibdev,
64                              const struct uapi_definition *def,
65                              u32 obj_key,
66                              u32 *cur_method_key)
67 {
68         struct uverbs_api_write_method *method_elm;
69         u32 method_key = obj_key;
70         bool exists;
71
72         if (def->write.is_ex)
73                 method_key |= uapi_key_write_ex_method(def->write.command_num);
74         else
75                 method_key |= uapi_key_write_method(def->write.command_num);
76
77         method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm),
78                                       &exists);
79         if (IS_ERR(method_elm))
80                 return PTR_ERR(method_elm);
81
82         if (WARN_ON(exists && (def->write.is_ex != method_elm->is_ex ||
83                                method_elm->handler_ex || method_elm->handler)))
84                 return -EINVAL;
85
86         method_elm->is_ex = def->write.is_ex;
87         if (def->write.is_ex) {
88                 method_elm->handler_ex = def->func_write_ex;
89
90                 method_elm->disabled = !(ibdev->uverbs_ex_cmd_mask &
91                                          BIT_ULL(def->write.command_num));
92         } else {
93                 method_elm->handler = def->func_write;
94
95                 method_elm->disabled = !(ibdev->uverbs_cmd_mask &
96                                          BIT_ULL(def->write.command_num));
97         }
98
99         if (!def->write.is_ex && def->func_write) {
100                 method_elm->has_udata = def->write.has_udata;
101                 method_elm->has_resp = def->write.has_resp;
102                 method_elm->req_size = def->write.req_size;
103                 method_elm->resp_size = def->write.resp_size;
104         }
105
106         *cur_method_key = method_key;
107         return 0;
108 }
109
110 static int uapi_merge_method(struct uverbs_api *uapi,
111                              struct uverbs_api_object *obj_elm, u32 obj_key,
112                              const struct uverbs_method_def *method,
113                              bool is_driver)
114 {
115         u32 method_key = obj_key | uapi_key_ioctl_method(method->id);
116         struct uverbs_api_ioctl_method *method_elm;
117         unsigned int i;
118         bool exists;
119
120         if (!method->attrs)
121                 return 0;
122
123         method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm),
124                                       &exists);
125         if (IS_ERR(method_elm))
126                 return PTR_ERR(method_elm);
127         if (exists) {
128                 /*
129                  * This occurs when a driver uses ADD_UVERBS_ATTRIBUTES_SIMPLE
130                  */
131                 if (WARN_ON(method->handler))
132                         return -EINVAL;
133         } else {
134                 WARN_ON(!method->handler);
135                 rcu_assign_pointer(method_elm->handler, method->handler);
136                 if (method->handler != uverbs_destroy_def_handler)
137                         method_elm->driver_method = is_driver;
138         }
139
140         for (i = 0; i != method->num_attrs; i++) {
141                 const struct uverbs_attr_def *attr = (*method->attrs)[i];
142                 struct uverbs_api_attr *attr_slot;
143
144                 if (!attr)
145                         continue;
146
147                 /*
148                  * ENUM_IN contains the 'ids' pointer to the driver's .rodata,
149                  * so if it is specified by a driver then it always makes this
150                  * into a driver method.
151                  */
152                 if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN)
153                         method_elm->driver_method |= is_driver;
154
155                 /*
156                  * Like other uobject based things we only support a single
157                  * uobject being NEW'd or DESTROY'd
158                  */
159                 if (attr->attr.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
160                         u8 access = attr->attr.u2.objs_arr.access;
161
162                         if (WARN_ON(access == UVERBS_ACCESS_NEW ||
163                                     access == UVERBS_ACCESS_DESTROY))
164                                 return -EINVAL;
165                 }
166
167                 attr_slot =
168                         uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id),
169                                      sizeof(*attr_slot));
170                 /* Attributes are not allowed to be modified by drivers */
171                 if (IS_ERR(attr_slot))
172                         return PTR_ERR(attr_slot);
173
174                 attr_slot->spec = attr->attr;
175         }
176
177         return 0;
178 }
179
180 static int uapi_merge_obj_tree(struct uverbs_api *uapi,
181                                const struct uverbs_object_def *obj,
182                                bool is_driver)
183 {
184         struct uverbs_api_object *obj_elm;
185         unsigned int i;
186         u32 obj_key;
187         bool exists;
188         int rc;
189
190         obj_key = uapi_key_obj(obj->id);
191         obj_elm = uapi_add_get_elm(uapi, obj_key, sizeof(*obj_elm), &exists);
192         if (IS_ERR(obj_elm))
193                 return PTR_ERR(obj_elm);
194
195         if (obj->type_attrs) {
196                 if (WARN_ON(obj_elm->type_attrs))
197                         return -EINVAL;
198
199                 obj_elm->type_attrs = obj->type_attrs;
200                 obj_elm->type_class = obj->type_attrs->type_class;
201                 /*
202                  * Today drivers are only permitted to use idr_class
203                  * types. They cannot use FD types because we currently have
204                  * no way to revoke the fops pointer after device
205                  * disassociation.
206                  */
207                 if (WARN_ON(is_driver &&
208                             obj->type_attrs->type_class != &uverbs_idr_class))
209                         return -EINVAL;
210         }
211
212         if (!obj->methods)
213                 return 0;
214
215         for (i = 0; i != obj->num_methods; i++) {
216                 const struct uverbs_method_def *method = (*obj->methods)[i];
217
218                 if (!method)
219                         continue;
220
221                 rc = uapi_merge_method(uapi, obj_elm, obj_key, method,
222                                        is_driver);
223                 if (rc)
224                         return rc;
225         }
226
227         return 0;
228 }
229
230 static int uapi_disable_elm(struct uverbs_api *uapi,
231                             const struct uapi_definition *def,
232                             u32 obj_key,
233                             u32 method_key)
234 {
235         bool exists;
236
237         if (def->scope == UAPI_SCOPE_OBJECT) {
238                 struct uverbs_api_object *obj_elm;
239
240                 obj_elm = uapi_add_get_elm(
241                         uapi, obj_key, sizeof(*obj_elm), &exists);
242                 if (IS_ERR(obj_elm))
243                         return PTR_ERR(obj_elm);
244                 obj_elm->disabled = 1;
245                 return 0;
246         }
247
248         if (def->scope == UAPI_SCOPE_METHOD &&
249             uapi_key_is_ioctl_method(method_key)) {
250                 struct uverbs_api_ioctl_method *method_elm;
251
252                 method_elm = uapi_add_get_elm(uapi, method_key,
253                                               sizeof(*method_elm), &exists);
254                 if (IS_ERR(method_elm))
255                         return PTR_ERR(method_elm);
256                 method_elm->disabled = 1;
257                 return 0;
258         }
259
260         if (def->scope == UAPI_SCOPE_METHOD &&
261             (uapi_key_is_write_method(method_key) ||
262              uapi_key_is_write_ex_method(method_key))) {
263                 struct uverbs_api_write_method *write_elm;
264
265                 write_elm = uapi_add_get_elm(uapi, method_key,
266                                              sizeof(*write_elm), &exists);
267                 if (IS_ERR(write_elm))
268                         return PTR_ERR(write_elm);
269                 write_elm->disabled = 1;
270                 return 0;
271         }
272
273         WARN_ON(true);
274         return -EINVAL;
275 }
276
277 static int uapi_merge_def(struct uverbs_api *uapi, struct ib_device *ibdev,
278                           const struct uapi_definition *def_list,
279                           bool is_driver)
280 {
281         const struct uapi_definition *def = def_list;
282         u32 cur_obj_key = UVERBS_API_KEY_ERR;
283         u32 cur_method_key = UVERBS_API_KEY_ERR;
284         bool exists;
285         int rc;
286
287         if (!def_list)
288                 return 0;
289
290         for (;; def++) {
291                 switch ((enum uapi_definition_kind)def->kind) {
292                 case UAPI_DEF_CHAIN:
293                         rc = uapi_merge_def(uapi, ibdev, def->chain, is_driver);
294                         if (rc)
295                                 return rc;
296                         continue;
297
298                 case UAPI_DEF_CHAIN_OBJ_TREE:
299                         if (WARN_ON(def->object_start.object_id !=
300                                     def->chain_obj_tree->id))
301                                 return -EINVAL;
302
303                         cur_obj_key = uapi_key_obj(def->object_start.object_id);
304                         rc = uapi_merge_obj_tree(uapi, def->chain_obj_tree,
305                                                  is_driver);
306                         if (rc)
307                                 return rc;
308                         continue;
309
310                 case UAPI_DEF_END:
311                         return 0;
312
313                 case UAPI_DEF_IS_SUPPORTED_DEV_FN: {
314                         void **ibdev_fn = (void *)ibdev + def->needs_fn_offset;
315
316                         if (*ibdev_fn)
317                                 continue;
318                         rc = uapi_disable_elm(
319                                 uapi, def, cur_obj_key, cur_method_key);
320                         if (rc)
321                                 return rc;
322                         continue;
323                 }
324
325                 case UAPI_DEF_IS_SUPPORTED_FUNC:
326                         if (def->func_is_supported(ibdev))
327                                 continue;
328                         rc = uapi_disable_elm(
329                                 uapi, def, cur_obj_key, cur_method_key);
330                         if (rc)
331                                 return rc;
332                         continue;
333
334                 case UAPI_DEF_OBJECT_START: {
335                         struct uverbs_api_object *obj_elm;
336
337                         cur_obj_key = uapi_key_obj(def->object_start.object_id);
338                         obj_elm = uapi_add_get_elm(uapi, cur_obj_key,
339                                                    sizeof(*obj_elm), &exists);
340                         if (IS_ERR(obj_elm))
341                                 return PTR_ERR(obj_elm);
342                         continue;
343                 }
344
345                 case UAPI_DEF_WRITE:
346                         rc = uapi_create_write(
347                                 uapi, ibdev, def, cur_obj_key, &cur_method_key);
348                         if (rc)
349                                 return rc;
350                         continue;
351                 }
352                 WARN_ON(true);
353                 return -EINVAL;
354         }
355 }
356
357 static int
358 uapi_finalize_ioctl_method(struct uverbs_api *uapi,
359                            struct uverbs_api_ioctl_method *method_elm,
360                            u32 method_key)
361 {
362         struct radix_tree_iter iter;
363         unsigned int num_attrs = 0;
364         unsigned int max_bkey = 0;
365         bool single_uobj = false;
366         void __rcu **slot;
367
368         method_elm->destroy_bkey = UVERBS_API_ATTR_BKEY_LEN;
369         radix_tree_for_each_slot (slot, &uapi->radix, &iter,
370                                   uapi_key_attrs_start(method_key)) {
371                 struct uverbs_api_attr *elm =
372                         rcu_dereference_protected(*slot, true);
373                 u32 attr_key = iter.index & UVERBS_API_ATTR_KEY_MASK;
374                 u32 attr_bkey = uapi_bkey_attr(attr_key);
375                 u8 type = elm->spec.type;
376
377                 if (uapi_key_attr_to_ioctl_method(iter.index) !=
378                     uapi_key_attr_to_ioctl_method(method_key))
379                         break;
380
381                 if (elm->spec.mandatory)
382                         __set_bit(attr_bkey, method_elm->attr_mandatory);
383
384                 if (type == UVERBS_ATTR_TYPE_IDR ||
385                     type == UVERBS_ATTR_TYPE_FD) {
386                         u8 access = elm->spec.u.obj.access;
387
388                         /*
389                          * Verbs specs may only have one NEW/DESTROY, we don't
390                          * have the infrastructure to abort multiple NEW's or
391                          * cope with multiple DESTROY failure.
392                          */
393                         if (access == UVERBS_ACCESS_NEW ||
394                             access == UVERBS_ACCESS_DESTROY) {
395                                 if (WARN_ON(single_uobj))
396                                         return -EINVAL;
397
398                                 single_uobj = true;
399                                 if (WARN_ON(!elm->spec.mandatory))
400                                         return -EINVAL;
401                         }
402
403                         if (access == UVERBS_ACCESS_DESTROY)
404                                 method_elm->destroy_bkey = attr_bkey;
405                 }
406
407                 max_bkey = max(max_bkey, attr_bkey);
408                 num_attrs++;
409         }
410
411         method_elm->key_bitmap_len = max_bkey + 1;
412         WARN_ON(method_elm->key_bitmap_len > UVERBS_API_ATTR_BKEY_LEN);
413
414         uapi_compute_bundle_size(method_elm, num_attrs);
415         return 0;
416 }
417
418 static int uapi_finalize(struct uverbs_api *uapi)
419 {
420         const struct uverbs_api_write_method **data;
421         unsigned long max_write_ex = 0;
422         unsigned long max_write = 0;
423         struct radix_tree_iter iter;
424         void __rcu **slot;
425         int rc;
426         int i;
427
428         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
429                 struct uverbs_api_ioctl_method *method_elm =
430                         rcu_dereference_protected(*slot, true);
431
432                 if (uapi_key_is_ioctl_method(iter.index)) {
433                         rc = uapi_finalize_ioctl_method(uapi, method_elm,
434                                                         iter.index);
435                         if (rc)
436                                 return rc;
437                 }
438
439                 if (uapi_key_is_write_method(iter.index))
440                         max_write = max(max_write,
441                                         iter.index & UVERBS_API_ATTR_KEY_MASK);
442                 if (uapi_key_is_write_ex_method(iter.index))
443                         max_write_ex =
444                                 max(max_write_ex,
445                                     iter.index & UVERBS_API_ATTR_KEY_MASK);
446         }
447
448         uapi->notsupp_method.handler = ib_uverbs_notsupp;
449         uapi->notsupp_method.handler_ex = ib_uverbs_ex_notsupp;
450         uapi->num_write = max_write + 1;
451         uapi->num_write_ex = max_write_ex + 1;
452         data = kmalloc_array(uapi->num_write + uapi->num_write_ex,
453                              sizeof(*uapi->write_methods), GFP_KERNEL);
454         for (i = 0; i != uapi->num_write + uapi->num_write_ex; i++)
455                 data[i] = &uapi->notsupp_method;
456         uapi->write_methods = data;
457         uapi->write_ex_methods = data + uapi->num_write;
458
459         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
460                 if (uapi_key_is_write_method(iter.index))
461                         uapi->write_methods[iter.index &
462                                             UVERBS_API_ATTR_KEY_MASK] =
463                                 rcu_dereference_protected(*slot, true);
464                 if (uapi_key_is_write_ex_method(iter.index))
465                         uapi->write_ex_methods[iter.index &
466                                                UVERBS_API_ATTR_KEY_MASK] =
467                                 rcu_dereference_protected(*slot, true);
468         }
469
470         return 0;
471 }
472
473 static void uapi_remove_range(struct uverbs_api *uapi, u32 start, u32 last)
474 {
475         struct radix_tree_iter iter;
476         void __rcu **slot;
477
478         radix_tree_for_each_slot (slot, &uapi->radix, &iter, start) {
479                 if (iter.index > last)
480                         return;
481                 kfree(rcu_dereference_protected(*slot, true));
482                 radix_tree_iter_delete(&uapi->radix, &iter, slot);
483         }
484 }
485
486 static void uapi_remove_object(struct uverbs_api *uapi, u32 obj_key)
487 {
488         uapi_remove_range(uapi, obj_key,
489                           obj_key | UVERBS_API_METHOD_KEY_MASK |
490                                   UVERBS_API_ATTR_KEY_MASK);
491 }
492
493 static void uapi_remove_method(struct uverbs_api *uapi, u32 method_key)
494 {
495         uapi_remove_range(uapi, method_key,
496                           method_key | UVERBS_API_ATTR_KEY_MASK);
497 }
498
499
500 static u32 uapi_get_obj_id(struct uverbs_attr_spec *spec)
501 {
502         if (spec->type == UVERBS_ATTR_TYPE_IDR ||
503             spec->type == UVERBS_ATTR_TYPE_FD)
504                 return spec->u.obj.obj_type;
505         if (spec->type == UVERBS_ATTR_TYPE_IDRS_ARRAY)
506                 return spec->u2.objs_arr.obj_type;
507         return UVERBS_API_KEY_ERR;
508 }
509
510 static void uapi_key_okay(u32 key)
511 {
512         unsigned int count = 0;
513
514         if (uapi_key_is_object(key))
515                 count++;
516         if (uapi_key_is_ioctl_method(key))
517                 count++;
518         if (uapi_key_is_write_method(key))
519                 count++;
520         if (uapi_key_is_write_ex_method(key))
521                 count++;
522         if (uapi_key_is_attr(key))
523                 count++;
524         WARN(count != 1, "Bad count %d key=%x", count, key);
525 }
526
527 static void uapi_finalize_disable(struct uverbs_api *uapi)
528 {
529         struct radix_tree_iter iter;
530         u32 starting_key = 0;
531         bool scan_again = false;
532         void __rcu **slot;
533
534 again:
535         radix_tree_for_each_slot (slot, &uapi->radix, &iter, starting_key) {
536                 uapi_key_okay(iter.index);
537
538                 if (uapi_key_is_object(iter.index)) {
539                         struct uverbs_api_object *obj_elm =
540                                 rcu_dereference_protected(*slot, true);
541
542                         if (obj_elm->disabled) {
543                                 /* Have to check all the attrs again */
544                                 scan_again = true;
545                                 starting_key = iter.index;
546                                 uapi_remove_object(uapi, iter.index);
547                                 goto again;
548                         }
549                         continue;
550                 }
551
552                 if (uapi_key_is_ioctl_method(iter.index)) {
553                         struct uverbs_api_ioctl_method *method_elm =
554                                 rcu_dereference_protected(*slot, true);
555
556                         if (method_elm->disabled) {
557                                 starting_key = iter.index;
558                                 uapi_remove_method(uapi, iter.index);
559                                 goto again;
560                         }
561                         continue;
562                 }
563
564                 if (uapi_key_is_write_method(iter.index) ||
565                     uapi_key_is_write_ex_method(iter.index)) {
566                         struct uverbs_api_write_method *method_elm =
567                                 rcu_dereference_protected(*slot, true);
568
569                         if (method_elm->disabled) {
570                                 kfree(method_elm);
571                                 radix_tree_iter_delete(&uapi->radix, &iter, slot);
572                         }
573                         continue;
574                 }
575
576                 if (uapi_key_is_attr(iter.index)) {
577                         struct uverbs_api_attr *attr_elm =
578                                 rcu_dereference_protected(*slot, true);
579                         const struct uverbs_api_object *tmp_obj;
580                         u32 obj_key;
581
582                         /*
583                          * If the method has a mandatory object handle
584                          * attribute which relies on an object which is not
585                          * present then the entire method is uncallable.
586                          */
587                         if (!attr_elm->spec.mandatory)
588                                 continue;
589                         obj_key = uapi_get_obj_id(&attr_elm->spec);
590                         if (obj_key == UVERBS_API_KEY_ERR)
591                                 continue;
592                         tmp_obj = uapi_get_object(uapi, obj_key);
593                         if (tmp_obj && !tmp_obj->disabled)
594                                 continue;
595
596                         starting_key = iter.index;
597                         uapi_remove_method(
598                                 uapi,
599                                 iter.index & (UVERBS_API_OBJ_KEY_MASK |
600                                               UVERBS_API_METHOD_KEY_MASK));
601                         goto again;
602                 }
603
604                 WARN_ON(false);
605         }
606
607         if (!scan_again)
608                 return;
609         scan_again = false;
610         starting_key = 0;
611         goto again;
612 }
613
614 void uverbs_destroy_api(struct uverbs_api *uapi)
615 {
616         if (!uapi)
617                 return;
618
619         uapi_remove_range(uapi, 0, U32_MAX);
620         kfree(uapi->write_methods);
621         kfree(uapi);
622 }
623
624 static const struct uapi_definition uverbs_core_api[] = {
625         UAPI_DEF_CHAIN(uverbs_def_obj_counters),
626         UAPI_DEF_CHAIN(uverbs_def_obj_cq),
627         UAPI_DEF_CHAIN(uverbs_def_obj_dm),
628         UAPI_DEF_CHAIN(uverbs_def_obj_flow_action),
629         UAPI_DEF_CHAIN(uverbs_def_obj_intf),
630         UAPI_DEF_CHAIN(uverbs_def_obj_mr),
631         UAPI_DEF_CHAIN(uverbs_def_write_intf),
632         {},
633 };
634
635 struct uverbs_api *uverbs_alloc_api(struct ib_device *ibdev)
636 {
637         struct uverbs_api *uapi;
638         int rc;
639
640         uapi = kzalloc(sizeof(*uapi), GFP_KERNEL);
641         if (!uapi)
642                 return ERR_PTR(-ENOMEM);
643
644         INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL);
645         uapi->driver_id = ibdev->driver_id;
646
647         rc = uapi_merge_def(uapi, ibdev, uverbs_core_api, false);
648         if (rc)
649                 goto err;
650         rc = uapi_merge_def(uapi, ibdev, ibdev->driver_def, true);
651         if (rc)
652                 goto err;
653
654         uapi_finalize_disable(uapi);
655         rc = uapi_finalize(uapi);
656         if (rc)
657                 goto err;
658
659         return uapi;
660 err:
661         if (rc != -ENOMEM)
662                 dev_err(&ibdev->dev,
663                         "Setup of uverbs_api failed, kernel parsing tree description is not valid (%d)??\n",
664                         rc);
665
666         uverbs_destroy_api(uapi);
667         return ERR_PTR(rc);
668 }
669
670 /*
671  * The pre version is done before destroying the HW objects, it only blocks
672  * off method access. All methods that require the ib_dev or the module data
673  * must test one of these assignments prior to continuing.
674  */
675 void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev)
676 {
677         struct uverbs_api *uapi = uverbs_dev->uapi;
678         struct radix_tree_iter iter;
679         void __rcu **slot;
680
681         rcu_assign_pointer(uverbs_dev->ib_dev, NULL);
682
683         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
684                 if (uapi_key_is_ioctl_method(iter.index)) {
685                         struct uverbs_api_ioctl_method *method_elm =
686                                 rcu_dereference_protected(*slot, true);
687
688                         if (method_elm->driver_method)
689                                 rcu_assign_pointer(method_elm->handler, NULL);
690                 }
691         }
692
693         synchronize_srcu(&uverbs_dev->disassociate_srcu);
694 }
695
696 /*
697  * Called when a driver disassociates from the ib_uverbs_device. The
698  * assumption is that the driver module will unload after. Replace everything
699  * related to the driver with NULL as a safety measure.
700  */
701 void uverbs_disassociate_api(struct uverbs_api *uapi)
702 {
703         struct radix_tree_iter iter;
704         void __rcu **slot;
705
706         radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
707                 if (uapi_key_is_object(iter.index)) {
708                         struct uverbs_api_object *object_elm =
709                                 rcu_dereference_protected(*slot, true);
710
711                         /*
712                          * Some type_attrs are in the driver module. We don't
713                          * bother to keep track of which since there should be
714                          * no use of this after disassociate.
715                          */
716                         object_elm->type_attrs = NULL;
717                 } else if (uapi_key_is_attr(iter.index)) {
718                         struct uverbs_api_attr *elm =
719                                 rcu_dereference_protected(*slot, true);
720
721                         if (elm->spec.type == UVERBS_ATTR_TYPE_ENUM_IN)
722                                 elm->spec.u2.enum_def.ids = NULL;
723                 }
724         }
725 }