return -EFAULT;
}
EXPORT_SYMBOL(_ib_respond_udata);
+
+/*
+ * Must be called with the ufile->device->disassociate_srcu held, and the lock
+ * must be held until use of the ucontext is finished.
+ */
+struct ib_ucontext *ib_uverbs_get_ucontext_file(struct ib_uverbs_file *ufile)
+{
+ /*
+ * We do not hold the hw_destroy_rwsem lock for this flow, instead
+ * srcu is used. It does not matter if someone races this with
+ * get_context, we get NULL or valid ucontext.
+ */
+ struct ib_ucontext *ucontext = smp_load_acquire(&ufile->ucontext);
+
+ if (!srcu_dereference(ufile->device->ib_dev,
+ &ufile->device->disassociate_srcu))
+ return ERR_PTR(-EIO);
+
+ if (!ucontext)
+ return ERR_PTR(-EINVAL);
+
+ return ucontext;
+}
+EXPORT_SYMBOL(ib_uverbs_get_ucontext_file);
+
+int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs)
+{
+ return 0;
+}
+EXPORT_SYMBOL(uverbs_destroy_def_handler);
+
+/**
+ * _uverbs_alloc() - Quickly allocate memory for use with a bundle
+ * @bundle: The bundle
+ * @size: Number of bytes to allocate
+ * @flags: Allocator flags
+ *
+ * The bundle allocator is intended for allocations that are connected with
+ * processing the system call related to the bundle. The allocated memory is
+ * always freed once the system call completes, and cannot be freed any other
+ * way.
+ *
+ * This tries to use a small pool of pre-allocated memory for performance.
+ */
+__malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
+ gfp_t flags)
+{
+ struct bundle_priv *pbundle =
+ container_of(&bundle->hdr, struct bundle_priv, bundle);
+ size_t new_used;
+ void *res;
+
+ if (check_add_overflow(size, pbundle->internal_used, &new_used))
+ return ERR_PTR(-EOVERFLOW);
+
+ if (new_used > pbundle->internal_avail) {
+ struct bundle_alloc_head *buf;
+
+ buf = kvmalloc_flex(*buf, data, size, flags);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+ buf->next = pbundle->allocated_mem;
+ pbundle->allocated_mem = buf;
+ return buf->data;
+ }
+
+ res = (void *)pbundle->internal_buffer + pbundle->internal_used;
+ pbundle->internal_used =
+ ALIGN(new_used, sizeof(*pbundle->internal_buffer));
+ if (want_init_on_alloc(flags))
+ memset(res, 0, size);
+ return res;
+}
+EXPORT_SYMBOL(_uverbs_alloc);
+
+int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
+ const void *from, size_t size)
+{
+ const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
+ size_t min_size;
+
+ if (IS_ERR(attr))
+ return PTR_ERR(attr);
+
+ min_size = min_t(size_t, attr->ptr_attr.len, size);
+ if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
+ return -EFAULT;
+
+ return uverbs_set_output(bundle, attr);
+}
+EXPORT_SYMBOL(uverbs_copy_to);
+
+int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
+ size_t idx, const void *from, size_t size)
+{
+ const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
+
+ if (IS_ERR(attr))
+ return PTR_ERR(attr);
+
+ if (size < attr->ptr_attr.len) {
+ if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size,
+ attr->ptr_attr.len - size))
+ return -EFAULT;
+ }
+ return uverbs_copy_to(bundle, idx, from, size);
+}
+EXPORT_SYMBOL(uverbs_copy_to_struct_or_zero);
+
+int _uverbs_get_const_unsigned(u64 *to,
+ const struct uverbs_attr_bundle *attrs_bundle,
+ size_t idx, u64 upper_bound, u64 *def_val)
+{
+ const struct uverbs_attr *attr;
+
+ attr = uverbs_attr_get(attrs_bundle, idx);
+ if (IS_ERR(attr)) {
+ if ((PTR_ERR(attr) != -ENOENT) || !def_val)
+ return PTR_ERR(attr);
+
+ *to = *def_val;
+ } else {
+ *to = attr->ptr_attr.data;
+ }
+
+ if (*to > upper_bound)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL(_uverbs_get_const_unsigned);
+
+int _uverbs_get_const_signed(s64 *to,
+ const struct uverbs_attr_bundle *attrs_bundle,
+ size_t idx, s64 lower_bound, u64 upper_bound,
+ s64 *def_val)
+{
+ const struct uverbs_attr *attr;
+
+ attr = uverbs_attr_get(attrs_bundle, idx);
+ if (IS_ERR(attr)) {
+ if ((PTR_ERR(attr) != -ENOENT) || !def_val)
+ return PTR_ERR(attr);
+
+ *to = *def_val;
+ } else {
+ *to = attr->ptr_attr.data;
+ }
+
+ if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL(_uverbs_get_const_signed);
+
+int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
+ size_t idx, u64 allowed_bits)
+{
+ const struct uverbs_attr *attr;
+ u64 flags;
+
+ attr = uverbs_attr_get(attrs_bundle, idx);
+ /* Missing attribute means 0 flags */
+ if (IS_ERR(attr)) {
+ *to = 0;
+ return 0;
+ }
+
+ /*
+ * New userspace code should use 8 bytes to pass flags, but we
+ * transparently support old userspaces that were using 4 bytes as
+ * well.
+ */
+ if (attr->ptr_attr.len == 8)
+ flags = attr->ptr_attr.data;
+ else if (attr->ptr_attr.len == 4)
+ flags = *(u32 *)&attr->ptr_attr.data;
+ else
+ return -EINVAL;
+
+ if (flags & ~allowed_bits)
+ return -EINVAL;
+
+ *to = flags;
+ return 0;
+}
+EXPORT_SYMBOL(uverbs_get_flags64);
+
+int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
+ size_t idx, u64 allowed_bits)
+{
+ u64 flags;
+ int ret;
+
+ ret = uverbs_get_flags64(&flags, attrs_bundle, idx, allowed_bits);
+ if (ret)
+ return ret;
+
+ if (flags > U32_MAX)
+ return -EINVAL;
+ *to = flags;
+
+ return 0;
+}
+EXPORT_SYMBOL(uverbs_get_flags32);
+
+/* Once called an abort will call through to the type's destroy_hw() */
+void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
+ u16 idx)
+{
+ struct bundle_priv *pbundle =
+ container_of(&bundle->hdr, struct bundle_priv, bundle);
+
+ __set_bit(uapi_bkey_attr(uapi_key_attr(idx)),
+ pbundle->uobj_hw_obj_valid);
+}
+EXPORT_SYMBOL(uverbs_finalize_uobj_create);
u64 internal_buffer[32];
};
+static inline int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
+ const struct uverbs_attr *attr)
+{
+ struct bundle_priv *pbundle =
+ container_of(&bundle->hdr, struct bundle_priv, bundle);
+ u16 flags;
+
+ flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
+ UVERBS_ATTR_F_VALID_OUTPUT;
+ if (put_user(flags,
+ &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
+ return -EFAULT;
+ return 0;
+}
+
long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
struct ib_uverbs_flow_spec {
WARN_ON_ONCE(method_elm->bundle_size > PAGE_SIZE);
}
-/**
- * _uverbs_alloc() - Quickly allocate memory for use with a bundle
- * @bundle: The bundle
- * @size: Number of bytes to allocate
- * @flags: Allocator flags
- *
- * The bundle allocator is intended for allocations that are connected with
- * processing the system call related to the bundle. The allocated memory is
- * always freed once the system call completes, and cannot be freed any other
- * way.
- *
- * This tries to use a small pool of pre-allocated memory for performance.
- */
-__malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
- gfp_t flags)
-{
- struct bundle_priv *pbundle =
- container_of(&bundle->hdr, struct bundle_priv, bundle);
- size_t new_used;
- void *res;
-
- if (check_add_overflow(size, pbundle->internal_used, &new_used))
- return ERR_PTR(-EOVERFLOW);
-
- if (new_used > pbundle->internal_avail) {
- struct bundle_alloc_head *buf;
-
- buf = kvmalloc_flex(*buf, data, size, flags);
- if (!buf)
- return ERR_PTR(-ENOMEM);
- buf->next = pbundle->allocated_mem;
- pbundle->allocated_mem = buf;
- return buf->data;
- }
-
- res = (void *)pbundle->internal_buffer + pbundle->internal_used;
- pbundle->internal_used =
- ALIGN(new_used, sizeof(*pbundle->internal_buffer));
- if (want_init_on_alloc(flags))
- memset(res, 0, size);
- return res;
-}
-EXPORT_SYMBOL(_uverbs_alloc);
-
static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
u16 len)
{
0, uattr->len - len);
}
-static int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
- const struct uverbs_attr *attr)
-{
- struct bundle_priv *pbundle =
- container_of(&bundle->hdr, struct bundle_priv, bundle);
- u16 flags;
-
- flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
- UVERBS_ATTR_F_VALID_OUTPUT;
- if (put_user(flags,
- &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
- return -EFAULT;
- return 0;
-}
-
static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
const struct uverbs_api_attr *attr_uapi,
struct uverbs_objs_arr_attr *attr,
return err;
}
-int uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
- size_t idx, u64 allowed_bits)
-{
- const struct uverbs_attr *attr;
- u64 flags;
-
- attr = uverbs_attr_get(attrs_bundle, idx);
- /* Missing attribute means 0 flags */
- if (IS_ERR(attr)) {
- *to = 0;
- return 0;
- }
-
- /*
- * New userspace code should use 8 bytes to pass flags, but we
- * transparently support old userspaces that were using 4 bytes as
- * well.
- */
- if (attr->ptr_attr.len == 8)
- flags = attr->ptr_attr.data;
- else if (attr->ptr_attr.len == 4)
- flags = *(u32 *)&attr->ptr_attr.data;
- else
- return -EINVAL;
-
- if (flags & ~allowed_bits)
- return -EINVAL;
-
- *to = flags;
- return 0;
-}
-EXPORT_SYMBOL(uverbs_get_flags64);
-
-int uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle,
- size_t idx, u64 allowed_bits)
-{
- u64 flags;
- int ret;
-
- ret = uverbs_get_flags64(&flags, attrs_bundle, idx, allowed_bits);
- if (ret)
- return ret;
-
- if (flags > U32_MAX)
- return -EINVAL;
- *to = flags;
-
- return 0;
-}
-EXPORT_SYMBOL(uverbs_get_flags32);
-
/*
* Fill a ib_udata struct (core or uhw) using the given attribute IDs.
* This is primarily used to convert the UVERBS_ATTR_UHW() into the
}
}
-int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
- const void *from, size_t size)
-{
- const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
- size_t min_size;
-
- if (IS_ERR(attr))
- return PTR_ERR(attr);
-
- min_size = min_t(size_t, attr->ptr_attr.len, size);
- if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
- return -EFAULT;
-
- return uverbs_set_output(bundle, attr);
-}
-EXPORT_SYMBOL(uverbs_copy_to);
-
-
/*
* This is only used if the caller has directly used copy_to_use to write the
* data. It signals to user space that the buffer is filled in.
return uverbs_set_output(bundle, attr);
}
-
-int _uverbs_get_const_signed(s64 *to,
- const struct uverbs_attr_bundle *attrs_bundle,
- size_t idx, s64 lower_bound, u64 upper_bound,
- s64 *def_val)
-{
- const struct uverbs_attr *attr;
-
- attr = uverbs_attr_get(attrs_bundle, idx);
- if (IS_ERR(attr)) {
- if ((PTR_ERR(attr) != -ENOENT) || !def_val)
- return PTR_ERR(attr);
-
- *to = *def_val;
- } else {
- *to = attr->ptr_attr.data;
- }
-
- if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
- return -EINVAL;
-
- return 0;
-}
-EXPORT_SYMBOL(_uverbs_get_const_signed);
-
-int _uverbs_get_const_unsigned(u64 *to,
- const struct uverbs_attr_bundle *attrs_bundle,
- size_t idx, u64 upper_bound, u64 *def_val)
-{
- const struct uverbs_attr *attr;
-
- attr = uverbs_attr_get(attrs_bundle, idx);
- if (IS_ERR(attr)) {
- if ((PTR_ERR(attr) != -ENOENT) || !def_val)
- return PTR_ERR(attr);
-
- *to = *def_val;
- } else {
- *to = attr->ptr_attr.data;
- }
-
- if (*to > upper_bound)
- return -EINVAL;
-
- return 0;
-}
-EXPORT_SYMBOL(_uverbs_get_const_unsigned);
-
-int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
- size_t idx, const void *from, size_t size)
-{
- const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
-
- if (IS_ERR(attr))
- return PTR_ERR(attr);
-
- if (size < attr->ptr_attr.len) {
- if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size,
- attr->ptr_attr.len - size))
- return -EFAULT;
- }
- return uverbs_copy_to(bundle, idx, from, size);
-}
-EXPORT_SYMBOL(uverbs_copy_to_struct_or_zero);
-
-/* Once called an abort will call through to the type's destroy_hw() */
-void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
- u16 idx)
-{
- struct bundle_priv *pbundle =
- container_of(&bundle->hdr, struct bundle_priv, bundle);
-
- __set_bit(uapi_bkey_attr(uapi_key_attr(idx)),
- pbundle->uobj_hw_obj_valid);
-}
-EXPORT_SYMBOL(uverbs_finalize_uobj_create);
.devnode = uverbs_devnode,
};
-/*
- * Must be called with the ufile->device->disassociate_srcu held, and the lock
- * must be held until use of the ucontext is finished.
- */
-struct ib_ucontext *ib_uverbs_get_ucontext_file(struct ib_uverbs_file *ufile)
-{
- /*
- * We do not hold the hw_destroy_rwsem lock for this flow, instead
- * srcu is used. It does not matter if someone races this with
- * get_context, we get NULL or valid ucontext.
- */
- struct ib_ucontext *ucontext = smp_load_acquire(&ufile->ucontext);
-
- if (!srcu_dereference(ufile->device->ib_dev,
- &ufile->device->disassociate_srcu))
- return ERR_PTR(-EIO);
-
- if (!ucontext)
- return ERR_PTR(-EINVAL);
-
- return ucontext;
-}
-EXPORT_SYMBOL(ib_uverbs_get_ucontext_file);
-
int uverbs_dealloc_mw(struct ib_mw *mw)
{
struct ib_pd *pd = mw->pd;
ib_uverbs_free_event_queue(&file->ev_queue);
}
-int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs)
-{
- return 0;
-}
-EXPORT_SYMBOL(uverbs_destroy_def_handler);
-
DECLARE_UVERBS_NAMED_OBJECT(
UVERBS_OBJECT_COMP_CHANNEL,
UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_completion_event_file),