return ret;
}
+
+int uverbs_finalize_objects(struct uverbs_attr_bundle *attrs_bundle,
+ struct uverbs_attr_spec_hash * const *spec_hash,
+ size_t num,
+ bool commit)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < num; i++) {
+ struct uverbs_attr_bundle_hash *curr_bundle =
+ &attrs_bundle->hash[i];
+ const struct uverbs_attr_spec_hash *curr_spec_bucket =
+ spec_hash[i];
+ unsigned int j;
+
+ for (j = 0; j < curr_bundle->num_attrs; j++) {
+ struct uverbs_attr *attr;
+ const struct uverbs_attr_spec *spec;
+
+ if (!uverbs_attr_is_valid_in_hash(curr_bundle, j))
+ continue;
+
+ attr = &curr_bundle->attrs[j];
+ spec = &curr_spec_bucket->attrs[j];
+
+ if (spec->type == UVERBS_ATTR_TYPE_IDR ||
+ spec->type == UVERBS_ATTR_TYPE_FD) {
+ int current_ret;
+
+ current_ret = uverbs_finalize_object(attr->obj_attr.uobject,
+ spec->obj.access,
+ commit);
+ if (!ret)
+ ret = current_ret;
+ }
+ }
+ }
+ return ret;
+}
* applicable.
* This function could create (access == NEW), destroy (access == DESTROY)
* or unlock (access == READ || access == WRITE) objects if required.
- * The action will be finalized only when uverbs_finalize_object is called.
+ * The action will be finalized only when uverbs_finalize_object or
+ * uverbs_finalize_objects are called.
*/
struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_obj_type *type_attrs,
struct ib_ucontext *ucontext,
int uverbs_finalize_object(struct ib_uobject *uobj,
enum uverbs_obj_access access,
bool commit);
+/*
+ * Note that certain finalize stages could return a status:
+ * (a) alloc_commit could return a failure if the object is committed at the
+ * same time when the context is destroyed.
+ * (b) remove_commit could fail if the object wasn't destroyed successfully.
+ * Since multiple objects could be finalized in one transaction, it is very NOT
+ * recommended to have several finalize actions which have side effects.
+ * For example, it's NOT recommended to have a certain action which has both
+ * a commit action and a destroy action or two destroy objects in the same
+ * action. The rule of thumb is to have one destroy or commit action with
+ * multiple lookups.
+ * The first non zero return value of finalize_object is returned from this
+ * function. For example, this could happen when we couldn't destroy an
+ * object.
+ */
+int uverbs_finalize_objects(struct uverbs_attr_bundle *attrs_bundle,
+ struct uverbs_attr_spec_hash * const *spec_hash,
+ size_t num,
+ bool commit);
#endif /* RDMA_CORE_H */
* =======================================
*/
+enum uverbs_attr_type {
+ UVERBS_ATTR_TYPE_NA,
+ UVERBS_ATTR_TYPE_IDR,
+ UVERBS_ATTR_TYPE_FD,
+};
+
enum uverbs_obj_access {
UVERBS_ACCESS_READ,
UVERBS_ACCESS_WRITE,
UVERBS_ACCESS_DESTROY
};
+struct uverbs_attr_spec {
+ enum uverbs_attr_type type;
+ struct {
+ /*
+ * higher bits mean the namespace and lower bits mean
+ * the type id within the namespace.
+ */
+ u16 obj_type;
+ u8 access;
+ } obj;
+};
+
+struct uverbs_attr_spec_hash {
+ size_t num_attrs;
+ struct uverbs_attr_spec attrs[0];
+};
+
+struct uverbs_obj_attr {
+ struct ib_uobject *uobject;
+};
+
+struct uverbs_attr {
+ struct uverbs_obj_attr obj_attr;
+};
+
+struct uverbs_attr_bundle_hash {
+ /* if bit i is set, it means attrs[i] contains valid information */
+ unsigned long *valid_bitmap;
+ size_t num_attrs;
+ /*
+ * arrays of attributes, each element corresponds to the specification
+ * of the attribute in the same index.
+ */
+ struct uverbs_attr *attrs;
+};
+
+struct uverbs_attr_bundle {
+ size_t num_buckets;
+ struct uverbs_attr_bundle_hash hash[];
+};
+
+static inline bool uverbs_attr_is_valid_in_hash(const struct uverbs_attr_bundle_hash *attrs_hash,
+ unsigned int idx)
+{
+ return test_bit(idx, attrs_hash->valid_bitmap);
+}
+
#endif