method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm),
&exists); if (IS_ERR(method_elm)) return PTR_ERR(method_elm); if (exists) { /* * This occurs when a driver uses ADD_UVERBS_ATTRIBUTES_SIMPLE
*/ if (WARN_ON(method->handler)) return -EINVAL;
} else {
WARN_ON(!method->handler);
rcu_assign_pointer(method_elm->handler, method->handler); if (method->handler != uverbs_destroy_def_handler)
method_elm->driver_method = is_driver;
}
for (i = 0; i != method->num_attrs; i++) { conststruct uverbs_attr_def *attr = (*method->attrs)[i]; struct uverbs_api_attr *attr_slot;
if (!attr) continue;
/* * ENUM_IN contains the 'ids' pointer to the driver's .rodata, * so if it is specified by a driver then it always makes this * into a driver method.
*/ if (attr->attr.type == UVERBS_ATTR_TYPE_ENUM_IN)
method_elm->driver_method |= is_driver;
/* * Like other uobject based things we only support a single * uobject being NEW'd or DESTROY'd
*/ if (attr->attr.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
u8 access = attr->attr.u2.objs_arr.access;
attr_slot =
uapi_add_elm(uapi, method_key | uapi_key_attr(attr->id), sizeof(*attr_slot)); /* Attributes are not allowed to be modified by drivers */ if (IS_ERR(attr_slot)) return PTR_ERR(attr_slot);
if (obj->type_attrs) { if (WARN_ON(obj_elm->type_attrs)) return -EINVAL;
obj_elm->id = obj->id;
obj_elm->type_attrs = obj->type_attrs;
obj_elm->type_class = obj->type_attrs->type_class; /* * Today drivers are only permitted to use idr_class and * fd_class types. We can revoke the IDR types during * disassociation, and the FD types require the driver to use * struct file_operations.owner to prevent the driver module * code from unloading while the file is open. This provides * enough safety that uverbs_uobject_fd_release() will * continue to work. Drivers using FD are responsible to * handle disassociation of the device on their own.
*/ if (WARN_ON(is_driver &&
obj->type_attrs->type_class != &uverbs_idr_class &&
obj->type_attrs->type_class != &uverbs_fd_class)) return -EINVAL;
}
if (!obj->methods) return 0;
for (i = 0; i != obj->num_methods; i++) { conststruct uverbs_method_def *method = (*obj->methods)[i];
if (uapi_key_attr_to_ioctl_method(iter.index) !=
uapi_key_attr_to_ioctl_method(method_key)) break;
if (elm->spec.mandatory)
__set_bit(attr_bkey, method_elm->attr_mandatory);
if (elm->spec.is_udata)
method_elm->has_udata = true;
if (type == UVERBS_ATTR_TYPE_IDR ||
type == UVERBS_ATTR_TYPE_FD) {
u8 access = elm->spec.u.obj.access;
/* * Verbs specs may only have one NEW/DESTROY, we don't * have the infrastructure to abort multiple NEW's or * cope with multiple DESTROY failure.
*/ if (access == UVERBS_ACCESS_NEW ||
access == UVERBS_ACCESS_DESTROY) { if (WARN_ON(single_uobj)) return -EINVAL;
single_uobj = true; if (WARN_ON(!elm->spec.mandatory)) return -EINVAL;
}
if (access == UVERBS_ACCESS_DESTROY)
method_elm->destroy_bkey = attr_bkey;
}
if (uapi_key_is_object(key))
count++; if (uapi_key_is_ioctl_method(key))
count++; if (uapi_key_is_write_method(key))
count++; if (uapi_key_is_write_ex_method(key))
count++; if (uapi_key_is_attr(key))
count++;
WARN(count != 1, "Bad count %u key=%x", count, key);
}
if (uapi_key_is_object(iter.index)) { struct uverbs_api_object *obj_elm =
rcu_dereference_protected(*slot, true);
if (obj_elm->disabled) { /* Have to check all the attrs again */
scan_again = true;
starting_key = iter.index;
uapi_remove_object(uapi, iter.index); goto again;
} continue;
}
if (uapi_key_is_ioctl_method(iter.index)) { struct uverbs_api_ioctl_method *method_elm =
rcu_dereference_protected(*slot, true);
/* * If the method has a mandatory object handle * attribute which relies on an object which is not * present then the entire method is uncallable.
*/ if (!attr_elm->spec.mandatory) continue;
obj_key = uapi_get_obj_id(&attr_elm->spec); if (obj_key == UVERBS_API_KEY_ERR) continue;
tmp_obj = uapi_get_object(uapi, obj_key); if (IS_ERR(tmp_obj)) { if (PTR_ERR(tmp_obj) == -ENOMSG) continue;
} else { if (!tmp_obj->disabled) continue;
}
rc = uapi_merge_def(uapi, ibdev, uverbs_core_api, false); if (rc) goto err;
rc = uapi_merge_def(uapi, ibdev, ibdev->driver_def, true); if (rc) goto err;
uapi_finalize_disable(uapi);
rc = uapi_finalize(uapi); if (rc) goto err;
return uapi;
err: if (rc != -ENOMEM)
dev_err(&ibdev->dev, "Setup of uverbs_api failed, kernel parsing tree description is not valid (%d)??\n",
rc);
uverbs_destroy_api(uapi); return ERR_PTR(rc);
}
/* * The pre version is done before destroying the HW objects, it only blocks * off method access. All methods that require the ib_dev or the module data * must test one of these assignments prior to continuing.
*/ void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev)
{ struct uverbs_api *uapi = uverbs_dev->uapi; struct radix_tree_iter iter; void __rcu **slot;
/* * Called when a driver disassociates from the ib_uverbs_device. The * assumption is that the driver module will unload after. Replace everything * related to the driver with NULL as a safety measure.
*/ void uverbs_disassociate_api(struct uverbs_api *uapi)
{ struct radix_tree_iter iter; void __rcu **slot;
/* * Some type_attrs are in the driver module. We don't * bother to keep track of which since there should be * no use of this after disassociate.
*/
object_elm->type_attrs = NULL;
} elseif (uapi_key_is_attr(iter.index)) { struct uverbs_api_attr *elm =
rcu_dereference_protected(*slot, true);
if (elm->spec.type == UVERBS_ATTR_TYPE_ENUM_IN)
elm->spec.u2.enum_def.ids = NULL;
}
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.