diff mbox

[RFC,ABI,V5,02/10] RDMA/core: Add support for custom types

Message ID 1477579398-6875-3-git-send-email-matanb@mellanox.com (mailing list archive)
State RFC
Headers show

Commit Message

Matan Barak Oct. 27, 2016, 2:43 p.m. UTC
The new ioctl infrastructure supports driver specific objects.
Each such object type has a free function, allocation size and an
order of destruction. This information is embedded in the same
table describing the various action allowed on the object, similarly
to object oriented programming.

When a ucontext is created, a new list is created in this ib_ucontext.
This list contains all objects created under this ib_ucontext.
When a ib_ucontext is destroyed, we traverse this list several time
destroying the various objects by the order mentioned in the object
type description. If few object types have the same destruction order,
they are destroyed in an order opposite to their creation order.

Adding an object is done in two parts.
First, an object is allocated and added to IDR/fd table. Then, the
command's handlers (in downstream patches) could work on this object
and fill in its required details.
After a successful command, ib_uverbs_uobject_enable is called and
this user objects becomes ucontext visible.

Removing an uboject is done by calling ib_uverbs_uobject_remove.

We should make sure IDR (per-device) and list (per-ucontext) could
be accessed concurrently without corrupting them.

Signed-off-by: Matan Barak <matanb@mellanox.com>
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
---
 drivers/infiniband/core/Makefile      |   3 +-
 drivers/infiniband/core/device.c      |   1 +
 drivers/infiniband/core/rdma_core.c   | 489 ++++++++++++++++++++++++++++++++++
 drivers/infiniband/core/rdma_core.h   |  75 ++++++
 drivers/infiniband/core/uverbs.h      |   1 +
 drivers/infiniband/core/uverbs_main.c |   2 +-
 include/rdma/ib_verbs.h               |  28 +-
 include/rdma/uverbs_ioctl.h           | 195 ++++++++++++++
 8 files changed, 789 insertions(+), 5 deletions(-)
 create mode 100644 drivers/infiniband/core/rdma_core.c
 create mode 100644 drivers/infiniband/core/rdma_core.h
 create mode 100644 include/rdma/uverbs_ioctl.h

Comments

Hefty, Sean Oct. 30, 2016, 7:28 p.m. UTC | #1
I found this patch very hard to follow.  This was in part due to the output of the patch command itself, but also because there lacked sufficient documentation on what the new data structures were for and the terms being used.  As a result, I had to bounce around the patch to figure things out, adding comments as I went along, until I finally just gave up trying to read it.

> The new ioctl infrastructure supports driver specific objects.
> Each such object type has a free function, allocation size and an

You can replace the allocation size with an alloc function, to pair with the free call.  Then the object can be initialized by the user.

> order of destruction. This information is embedded in the same
> table describing the various action allowed on the object, similarly
> to object oriented programming.
> 
> When a ucontext is created, a new list is created in this ib_ucontext.
> This list contains all objects created under this ib_ucontext.
> When a ib_ucontext is destroyed, we traverse this list several time
> destroying the various objects by the order mentioned in the object
> type description. If few object types have the same destruction order,
> they are destroyed in an order opposite to their creation order.

Could we simply walk the list backwards, destroying all objects with a reference count of 1 - repeat if necessary?  Basically avoid complex rules for this.

In fact, it would be great if we could just cleanup the list in the reverse order that items were created.  Maybe this requires supporting a pre-cleanup handler, so that the driver can pluck items out of the list that may need to be destroyed out of order.

> Adding an object is done in two parts.
> First, an object is allocated and added to IDR/fd table. Then, the
> command's handlers (in downstream patches) could work on this object
> and fill in its required details.
> After a successful command, ib_uverbs_uobject_enable is called and
> this user objects becomes ucontext visible.

If you have a way to mark that an object is used for exclusive access, you may be able to use that instead of introducing a new variable.  (I.e. acquire the object's write lock).  I think we want to make an effort to minimize the size of the kernel structure needed to track every user space object (within reason).

> Removing an uboject is done by calling ib_uverbs_uobject_remove.
> 
> We should make sure IDR (per-device) and list (per-ucontext) could
> be accessed concurrently without corrupting them.
> 
> Signed-off-by: Matan Barak <matanb@mellanox.com>
> Signed-off-by: Haggai Eran <haggaie@mellanox.com>
> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
> ---

As a general comment, I do have concerns that the resulting generalized parsing of everything will negatively impact performance for operations that do have to transition into the kernel.  Not all devices offload all operations to user space.  Plus the resulting code is extremely difficult to read and non-trivial to use.  It's equivalent to reading C++ code that has 4 layers of inheritance with overrides to basic operators...

Pre and post operators per command that can do straightforward validation seem like a better option.


>  drivers/infiniband/core/Makefile      |   3 +-
>  drivers/infiniband/core/device.c      |   1 +
>  drivers/infiniband/core/rdma_core.c   | 489
> ++++++++++++++++++++++++++++++++++
>  drivers/infiniband/core/rdma_core.h   |  75 ++++++
>  drivers/infiniband/core/uverbs.h      |   1 +
>  drivers/infiniband/core/uverbs_main.c |   2 +-
>  include/rdma/ib_verbs.h               |  28 +-
>  include/rdma/uverbs_ioctl.h           | 195 ++++++++++++++
>  8 files changed, 789 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/infiniband/core/rdma_core.c
>  create mode 100644 drivers/infiniband/core/rdma_core.h
>  create mode 100644 include/rdma/uverbs_ioctl.h
> 
> diff --git a/drivers/infiniband/core/Makefile
> b/drivers/infiniband/core/Makefile
> index edaae9f..1819623 100644
> --- a/drivers/infiniband/core/Makefile
> +++ b/drivers/infiniband/core/Makefile
> @@ -28,4 +28,5 @@ ib_umad-y :=			user_mad.o
> 
>  ib_ucm-y :=			ucm.o
> 
> -ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o
> uverbs_marshall.o
> +ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o
> uverbs_marshall.o \
> +				rdma_core.o
> diff --git a/drivers/infiniband/core/device.c
> b/drivers/infiniband/core/device.c
> index c3b68f5..43994b1 100644
> --- a/drivers/infiniband/core/device.c
> +++ b/drivers/infiniband/core/device.c
> @@ -243,6 +243,7 @@ struct ib_device *ib_alloc_device(size_t size)
>  	spin_lock_init(&device->client_data_lock);
>  	INIT_LIST_HEAD(&device->client_data_list);
>  	INIT_LIST_HEAD(&device->port_list);
> +	INIT_LIST_HEAD(&device->type_list);
> 
>  	return device;
>  }
> diff --git a/drivers/infiniband/core/rdma_core.c
> b/drivers/infiniband/core/rdma_core.c
> new file mode 100644
> index 0000000..337abc2
> --- /dev/null
> +++ b/drivers/infiniband/core/rdma_core.c
> @@ -0,0 +1,489 @@
> +/*
> + * Copyright (c) 2016, Mellanox Technologies inc.  All rights
> reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#include <linux/file.h>
> +#include <linux/anon_inodes.h>
> +#include <rdma/ib_verbs.h>
> +#include "uverbs.h"
> +#include "rdma_core.h"
> +#include <rdma/uverbs_ioctl.h>
> +
> +const struct uverbs_type *uverbs_get_type(const struct ib_device
> *ibdev,
> +					  uint16_t type)
> +{
> +	const struct uverbs_types_group *groups = ibdev->types_group;
> +	const struct uverbs_types *types;
> +	int ret = groups->dist(&type, groups->priv);
> +
> +	if (ret >= groups->num_groups)
> +		return NULL;
> +
> +	types = groups->type_groups[ret];
> +
> +	if (type >= types->num_types)
> +		return NULL;
> +
> +	return types->types[type];
> +}
> +
> +static int uverbs_lock_object(struct ib_uobject *uobj,
> +			      enum uverbs_idr_access access)
> +{
> +	if (access == UVERBS_IDR_ACCESS_READ)
> +		return down_read_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
> +
> +	/* lock is either WRITE or DESTROY - should be exclusive */
> +	return down_write_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;

This function could take the lock type directly (read or write), versus inferring it based on some other access type.

> +}
> +
> +static struct ib_uobject *get_uobj(int id, struct ib_ucontext
> *context)
> +{
> +	struct ib_uobject *uobj;
> +
> +	rcu_read_lock();
> +	uobj = idr_find(&context->device->idr, id);
> +	if (uobj && uobj->live) {
> +		if (uobj->context != context)
> +			uobj = NULL;
> +	}
> +	rcu_read_unlock();
> +
> +	return uobj;
> +}
> +
> +struct ib_ucontext_lock {
> +	struct kref  ref;
> +	/* locking the uobjects_list */
> +	struct mutex lock;
> +};
> +
> +static void init_uobjects_list_lock(struct ib_ucontext_lock *lock)
> +{
> +	mutex_init(&lock->lock);
> +	kref_init(&lock->ref);
> +}
> +
> +static void release_uobjects_list_lock(struct kref *ref)
> +{
> +	struct ib_ucontext_lock *lock = container_of(ref,
> +						     struct ib_ucontext_lock,
> +						     ref);
> +
> +	kfree(lock);
> +}
> +
> +static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
> +		      struct ib_ucontext *context)
> +{
> +	init_rwsem(&uobj->usecnt);
> +	uobj->user_handle = user_handle;
> +	uobj->context     = context;
> +	uobj->live        = 0;
> +}
> +
> +static int add_uobj(struct ib_uobject *uobj)
> +{
> +	int ret;
> +
> +	idr_preload(GFP_KERNEL);
> +	spin_lock(&uobj->context->device->idr_lock);
> +
> +	ret = idr_alloc(&uobj->context->device->idr, uobj, 0, 0,
> GFP_NOWAIT);
> +	if (ret >= 0)
> +		uobj->id = ret;
> +
> +	spin_unlock(&uobj->context->device->idr_lock);
> +	idr_preload_end();
> +
> +	return ret < 0 ? ret : 0;
> +}
> +
> +static void remove_uobj(struct ib_uobject *uobj)
> +{
> +	spin_lock(&uobj->context->device->idr_lock);
> +	idr_remove(&uobj->context->device->idr, uobj->id);
> +	spin_unlock(&uobj->context->device->idr_lock);
> +}
> +
> +static void put_uobj(struct ib_uobject *uobj)
> +{
> +	kfree_rcu(uobj, rcu);
> +}
> +
> +static struct ib_uobject *get_uobject_from_context(struct ib_ucontext
> *ucontext,
> +						   const struct
> uverbs_type_alloc_action *type,
> +						   u32 idr,
> +						   enum uverbs_idr_access access)
> +{
> +	struct ib_uobject *uobj;
> +	int ret;
> +
> +	rcu_read_lock();
> +	uobj = get_uobj(idr, ucontext);
> +	if (!uobj)
> +		goto free;
> +
> +	if (uobj->type != type) {
> +		uobj = NULL;
> +		goto free;
> +	}
> +
> +	ret = uverbs_lock_object(uobj, access);
> +	if (ret)
> +		uobj = ERR_PTR(ret);
> +free:
> +	rcu_read_unlock();
> +	return uobj;
> +
> +	return NULL;
> +}
> +
> +static int ib_uverbs_uobject_add(struct ib_uobject *uobject,
> +				 const struct uverbs_type_alloc_action
> *uobject_type)
> +{
> +	uobject->type = uobject_type;
> +	return add_uobj(uobject);
> +}
> +
> +struct ib_uobject *uverbs_get_type_from_idr(const struct
> uverbs_type_alloc_action *type,
> +					    struct ib_ucontext *ucontext,
> +					    enum uverbs_idr_access access,
> +					    uint32_t idr)
> +{
> +	struct ib_uobject *uobj;
> +	int ret;
> +
> +	if (access == UVERBS_IDR_ACCESS_NEW) {
> +		uobj = kmalloc(type->obj_size, GFP_KERNEL);
> +		if (!uobj)
> +			return ERR_PTR(-ENOMEM);
> +
> +		init_uobj(uobj, 0, ucontext);
> +
> +		/* lock idr */

Command to lock idr, but no lock is obtained.

> +		ret = ib_uverbs_uobject_add(uobj, type);
> +		if (ret) {
> +			kfree(uobj);
> +			return ERR_PTR(ret);
> +		}
> +
> +	} else {
> +		uobj = get_uobject_from_context(ucontext, type, idr,
> +						access);
> +
> +		if (!uobj)
> +			return ERR_PTR(-ENOENT);
> +	}
> +
> +	return uobj;
> +}
> +
> +struct ib_uobject *uverbs_get_type_from_fd(const struct
> uverbs_type_alloc_action *type,
> +					   struct ib_ucontext *ucontext,
> +					   enum uverbs_idr_access access,
> +					   int fd)
> +{
> +	if (access == UVERBS_IDR_ACCESS_NEW) {
> +		int _fd;
> +		struct ib_uobject *uobj = NULL;
> +		struct file *filp;
> +
> +		_fd = get_unused_fd_flags(O_CLOEXEC);
> +		if (_fd < 0 || WARN_ON(type->obj_size < sizeof(struct
> ib_uobject)))
> +			return ERR_PTR(_fd);
> +
> +		uobj = kmalloc(type->obj_size, GFP_KERNEL);
> +		init_uobj(uobj, 0, ucontext);
> +
> +		if (!uobj)
> +			return ERR_PTR(-ENOMEM);
> +
> +		filp = anon_inode_getfile(type->fd.name, type->fd.fops,
> +					  uobj + 1, type->fd.flags);
> +		if (IS_ERR(filp)) {
> +			put_unused_fd(_fd);
> +			kfree(uobj);
> +			return (void *)filp;
> +		}
> +
> +		uobj->type = type;
> +		uobj->id = _fd;
> +		uobj->object = filp;
> +
> +		return uobj;
> +	} else if (access == UVERBS_IDR_ACCESS_READ) {
> +		struct file *f = fget(fd);
> +		struct ib_uobject *uobject;
> +
> +		if (!f)
> +			return ERR_PTR(-EBADF);
> +
> +		uobject = f->private_data - sizeof(struct ib_uobject);
> +		if (f->f_op != type->fd.fops ||
> +		    !uobject->live) {
> +			fput(f);
> +			return ERR_PTR(-EBADF);
> +		}
> +
> +		/*
> +		 * No need to protect it with a ref count, as fget
> increases
> +		 * f_count.
> +		 */
> +		return uobject;
> +	} else {
> +		return ERR_PTR(-EOPNOTSUPP);
> +	}
> +}
> +
> +static void ib_uverbs_uobject_enable(struct ib_uobject *uobject)
> +{
> +	mutex_lock(&uobject->context->uobjects_lock->lock);
> +	list_add(&uobject->list, &uobject->context->uobjects);
> +	mutex_unlock(&uobject->context->uobjects_lock->lock);

Why not just insert the object into the list on creation?

> +	uobject->live = 1;

See my comments above on removing the live field.

> +}
> +
> +static void ib_uverbs_uobject_remove(struct ib_uobject *uobject, bool
> lock)
> +{
> +	/*
> +	 * Calling remove requires exclusive access, so it's not possible
> +	 * another thread will use our object.
> +	 */
> +	uobject->live = 0;
> +	uobject->type->free_fn(uobject->type, uobject);
> +	if (lock)
> +		mutex_lock(&uobject->context->uobjects_lock->lock);
> +	list_del(&uobject->list);
> +	if (lock)
> +		mutex_unlock(&uobject->context->uobjects_lock->lock);
> +	remove_uobj(uobject);
> +	put_uobj(uobject);
> +}
> +
> +static void uverbs_unlock_idr(struct ib_uobject *uobj,
> +			      enum uverbs_idr_access access,
> +			      bool success)
> +{
> +	switch (access) {
> +	case UVERBS_IDR_ACCESS_READ:
> +		up_read(&uobj->usecnt);
> +		break;
> +	case UVERBS_IDR_ACCESS_NEW:
> +		if (success) {
> +			ib_uverbs_uobject_enable(uobj);
> +		} else {
> +			remove_uobj(uobj);
> +			put_uobj(uobj);
> +		}
> +		break;
> +	case UVERBS_IDR_ACCESS_WRITE:
> +		up_write(&uobj->usecnt);
> +		break;
> +	case UVERBS_IDR_ACCESS_DESTROY:
> +		if (success)
> +			ib_uverbs_uobject_remove(uobj, true);
> +		else
> +			up_write(&uobj->usecnt);
> +		break;
> +	}
> +}
> +
> +static void uverbs_unlock_fd(struct ib_uobject *uobj,
> +			     enum uverbs_idr_access access,
> +			     bool success)
> +{
> +	struct file *filp = uobj->object;
> +
> +	if (access == UVERBS_IDR_ACCESS_NEW) {
> +		if (success) {
> +			kref_get(&uobj->context->ufile->ref);
> +			uobj->uobjects_lock = uobj->context->uobjects_lock;
> +			kref_get(&uobj->uobjects_lock->ref);
> +			ib_uverbs_uobject_enable(uobj);
> +			fd_install(uobj->id, uobj->object);

I don't get this.  The function is unlocking something, but there are calls to get krefs?

> +		} else {
> +			fput(uobj->object);
> +			put_unused_fd(uobj->id);
> +			kfree(uobj);
> +		}
> +	} else {
> +		fput(filp);
> +	}
> +}
> +
> +void uverbs_unlock_object(struct ib_uobject *uobj,
> +			  enum uverbs_idr_access access,
> +			  bool success)
> +{
> +	if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
> +		uverbs_unlock_idr(uobj, access, success);
> +	else if (uobj->type->type == UVERBS_ATTR_TYPE_FD)
> +		uverbs_unlock_fd(uobj, access, success);
> +	else
> +		WARN_ON(true);
> +}
> +
> +static void ib_uverbs_remove_fd(struct ib_uobject *uobject)
> +{
> +	/*
> +	 * user should release the uobject in the release
> +	 * callback.
> +	 */
> +	if (uobject->live) {
> +		uobject->live = 0;
> +		list_del(&uobject->list);
> +		uobject->type->free_fn(uobject->type, uobject);
> +		kref_put(&uobject->context->ufile->ref,
> ib_uverbs_release_file);
> +		uobject->context = NULL;
> +	}
> +}
> +
> +void ib_uverbs_close_fd(struct file *f)
> +{
> +	struct ib_uobject *uobject = f->private_data - sizeof(struct
> ib_uobject);
> +
> +	mutex_lock(&uobject->uobjects_lock->lock);
> +	if (uobject->live) {
> +		uobject->live = 0;
> +		list_del(&uobject->list);
> +		kref_put(&uobject->context->ufile->ref,
> ib_uverbs_release_file);
> +		uobject->context = NULL;
> +	}
> +	mutex_unlock(&uobject->uobjects_lock->lock);
> +	kref_put(&uobject->uobjects_lock->ref,
> release_uobjects_list_lock);
> +}
> +
> +void ib_uverbs_cleanup_fd(void *private_data)
> +{
> +	struct ib_uboject *uobject = private_data - sizeof(struct
> ib_uobject);
> +
> +	kfree(uobject);
> +}
> +
> +void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
> +			   size_t num,
> +			   const struct uverbs_action_spec *spec,
> +			   bool success)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < num; i++) {
> +		struct uverbs_attr_array *attr_spec_array = &attr_array[i];
> +		const struct uverbs_attr_group_spec *group_spec =
> +			spec->attr_groups[i];
> +		unsigned int j;
> +
> +		for (j = 0; j < attr_spec_array->num_attrs; j++) {
> +			struct uverbs_attr *attr = &attr_spec_array-
> >attrs[j];
> +			struct uverbs_attr_spec *spec = &group_spec-
> >attrs[j];
> +
> +			if (!attr->valid)
> +				continue;
> +
> +			if (spec->type == UVERBS_ATTR_TYPE_IDR ||
> +			    spec->type == UVERBS_ATTR_TYPE_FD)
> +				/*
> +				 * refcounts should be handled at the object
> +				 * level and not at the uobject level.
> +				 */
> +				uverbs_unlock_object(attr->obj_attr.uobject,
> +						     spec->obj.access, success);
> +		}
> +	}
> +}
> +
> +static unsigned int get_type_orders(const struct uverbs_types_group
> *types_group)
> +{
> +	unsigned int i;
> +	unsigned int max = 0;
> +
> +	for (i = 0; i < types_group->num_groups; i++) {
> +		unsigned int j;
> +		const struct uverbs_types *types = types_group-
> >type_groups[i];
> +
> +		for (j = 0; j < types->num_types; j++) {
> +			if (!types->types[j] || !types->types[j]->alloc)
> +				continue;
> +			if (types->types[j]->alloc->order > max)
> +				max = types->types[j]->alloc->order;
> +		}
> +	}
> +
> +	return max;
> +}
> +
> +void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext
> *ucontext,
> +					     const struct uverbs_types_group
> *types_group)
> +{
> +	unsigned int num_orders = get_type_orders(types_group);
> +	unsigned int i;
> +
> +	for (i = 0; i <= num_orders; i++) {
> +		struct ib_uobject *obj, *next_obj;
> +
> +		/*
> +		 * No need to take lock here, as cleanup should be called
> +		 * after all commands finished executing. Newly executed
> +		 * commands should fail.
> +		 */
> +		mutex_lock(&ucontext->uobjects_lock->lock);

It's really confusing to see a comment about 'no need to take lock' immediately followed by a call to lock.

> +		list_for_each_entry_safe(obj, next_obj, &ucontext-
> >uobjects,
> +					 list)
> +			if (obj->type->order == i) {
> +				if (obj->type->type == UVERBS_ATTR_TYPE_IDR)
> +					ib_uverbs_uobject_remove(obj, false);
> +				else
> +					ib_uverbs_remove_fd(obj);
> +			}
> +		mutex_unlock(&ucontext->uobjects_lock->lock);
> +	}
> +	kref_put(&ucontext->uobjects_lock->ref,
> release_uobjects_list_lock);
> +}
> +
> +int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext
> *ucontext)

Please work on the function names.  This is horrendously long and still doesn't help describe what it does.

> +{
> +	ucontext->uobjects_lock = kmalloc(sizeof(*ucontext-
> >uobjects_lock),
> +					  GFP_KERNEL);
> +	if (!ucontext->uobjects_lock)
> +		return -ENOMEM;
> +
> +	init_uobjects_list_lock(ucontext->uobjects_lock);
> +	INIT_LIST_HEAD(&ucontext->uobjects);
> +
> +	return 0;
> +}
> +
> +void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext
> *ucontext)
> +{
> +	kfree(ucontext->uobjects_lock);
> +}

No need to wrap a call to 'free'.

> +
> diff --git a/drivers/infiniband/core/rdma_core.h
> b/drivers/infiniband/core/rdma_core.h
> new file mode 100644
> index 0000000..8990115
> --- /dev/null
> +++ b/drivers/infiniband/core/rdma_core.h
> @@ -0,0 +1,75 @@
> +/*
> + * Copyright (c) 2005 Topspin Communications.  All rights reserved.
> + * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
> + * Copyright (c) 2005-2016 Mellanox Technologies. All rights reserved.
> + * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
> + * Copyright (c) 2005 PathScale, Inc. All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#ifndef UOBJECT_H
> +#define UOBJECT_H
> +
> +#include <linux/idr.h>
> +#include <rdma/uverbs_ioctl.h>
> +#include <rdma/ib_verbs.h>
> +#include <linux/mutex.h>
> +
> +const struct uverbs_type *uverbs_get_type(const struct ib_device
> *ibdev,
> +					  uint16_t type);
> +struct ib_uobject *uverbs_get_type_from_idr(const struct
> uverbs_type_alloc_action *type,
> +					    struct ib_ucontext *ucontext,
> +					    enum uverbs_idr_access access,
> +					    uint32_t idr);
> +struct ib_uobject *uverbs_get_type_from_fd(const struct
> uverbs_type_alloc_action *type,
> +					   struct ib_ucontext *ucontext,
> +					   enum uverbs_idr_access access,
> +					   int fd);
> +void uverbs_unlock_object(struct ib_uobject *uobj,
> +			  enum uverbs_idr_access access,
> +			  bool success);
> +void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
> +			   size_t num,
> +			   const struct uverbs_action_spec *spec,
> +			   bool success);
> +
> +void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext
> *ucontext,
> +					     const struct uverbs_types_group
> *types_group);
> +int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext
> *ucontext);
> +void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext
> *ucontext);
> +void ib_uverbs_close_fd(struct file *f);
> +void ib_uverbs_cleanup_fd(void *private_data);
> +
> +static inline void *uverbs_fd_to_priv(struct ib_uobject *uobj)
> +{
> +	return uobj + 1;
> +}

This seems like a rather useless function.

> +
> +#endif /* UIDR_H */
> diff --git a/drivers/infiniband/core/uverbs.h
> b/drivers/infiniband/core/uverbs.h
> index 8074705..ae7d4b8 100644
> --- a/drivers/infiniband/core/uverbs.h
> +++ b/drivers/infiniband/core/uverbs.h
> @@ -180,6 +180,7 @@ void idr_remove_uobj(struct ib_uobject *uobj);
>  struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file
> *uverbs_file,
>  					struct ib_device *ib_dev,
>  					int is_async);
> +void ib_uverbs_release_file(struct kref *ref);
>  void ib_uverbs_free_async_event_file(struct ib_uverbs_file
> *uverbs_file);
>  struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
> 
> diff --git a/drivers/infiniband/core/uverbs_main.c
> b/drivers/infiniband/core/uverbs_main.c
> index f783723..e63357a 100644
> --- a/drivers/infiniband/core/uverbs_main.c
> +++ b/drivers/infiniband/core/uverbs_main.c
> @@ -341,7 +341,7 @@ static void ib_uverbs_comp_dev(struct
> ib_uverbs_device *dev)
>  	complete(&dev->comp);
>  }
> 
> -static void ib_uverbs_release_file(struct kref *ref)
> +void ib_uverbs_release_file(struct kref *ref)
>  {
>  	struct ib_uverbs_file *file =
>  		container_of(ref, struct ib_uverbs_file, ref);
> diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
> index b5d2075..7240615 100644
> --- a/include/rdma/ib_verbs.h
> +++ b/include/rdma/ib_verbs.h
> @@ -1329,8 +1329,11 @@ struct ib_fmr_attr {
> 
>  struct ib_umem;
> 
> +struct ib_ucontext_lock;
> +
>  struct ib_ucontext {
>  	struct ib_device       *device;
> +	struct ib_uverbs_file  *ufile;
>  	struct list_head	pd_list;
>  	struct list_head	mr_list;
>  	struct list_head	mw_list;
> @@ -1344,6 +1347,10 @@ struct ib_ucontext {
>  	struct list_head	rwq_ind_tbl_list;
>  	int			closing;
> 
> +	/* lock for uobjects list */
> +	struct ib_ucontext_lock	*uobjects_lock;
> +	struct list_head	uobjects;
> +
>  	struct pid             *tgid;
>  #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
>  	struct rb_root      umem_tree;
> @@ -1363,16 +1370,28 @@ struct ib_ucontext {
>  #endif
>  };
> 
> +struct uverbs_object_list;
> +
> +#define OLD_ABI_COMPAT
> +
>  struct ib_uobject {
>  	u64			user_handle;	/* handle given to us by userspace
> */
>  	struct ib_ucontext     *context;	/* associated user context
> */
>  	void		       *object;		/* containing object */
>  	struct list_head	list;		/* link to context's list */
> -	int			id;		/* index into kernel idr */
> -	struct kref		ref;
> -	struct rw_semaphore	mutex;		/* protects .live */
> +	int			id;		/* index into kernel idr/fd */
> +#ifdef OLD_ABI_COMPAT
> +	struct kref             ref;
> +#endif
> +	struct rw_semaphore	usecnt;		/* protects exclusive
> access */
> +#ifdef OLD_ABI_COMPAT
> +	struct rw_semaphore     mutex;          /* protects .live */
> +#endif
>  	struct rcu_head		rcu;		/* kfree_rcu() overhead */
>  	int			live;
> +
> +	const struct uverbs_type_alloc_action *type;
> +	struct ib_ucontext_lock	*uobjects_lock;
>  };
> 
>  struct ib_udata {
> @@ -2101,6 +2120,9 @@ struct ib_device {
>  	 */
>  	int (*get_port_immutable)(struct ib_device *, u8, struct
> ib_port_immutable *);
>  	void (*get_dev_fw_str)(struct ib_device *, char *str, size_t
> str_len);
> +	struct list_head type_list;
> +
> +	const struct uverbs_types_group	*types_group;
>  };
> 
>  struct ib_client {
> diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
> new file mode 100644
> index 0000000..2f50045
> --- /dev/null
> +++ b/include/rdma/uverbs_ioctl.h
> @@ -0,0 +1,195 @@
> +/*
> + * Copyright (c) 2016, Mellanox Technologies inc.  All rights
> reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses.  You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + *     Redistribution and use in source and binary forms, with or
> + *     without modification, are permitted provided that the following
> + *     conditions are met:
> + *
> + *      - Redistributions of source code must retain the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer.
> + *
> + *      - Redistributions in binary form must reproduce the above
> + *        copyright notice, this list of conditions and the following
> + *        disclaimer in the documentation and/or other materials
> + *        provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#ifndef _UVERBS_IOCTL_
> +#define _UVERBS_IOCTL_
> +
> +#include <linux/kernel.h>
> +
> +struct uverbs_object_type;
> +struct ib_ucontext;
> +struct ib_uobject;
> +struct ib_device;
> +struct uverbs_uobject_type;
> +
> +/*
> + * =======================================
> + *	Verbs action specifications
> + * =======================================
> + */

I intentionally used urdma (though condensed to 3 letters that I don't recall atm), rather than uverbs.  This will need to work with non-verbs devices and interfaces -- again, consider how this fits with the rdma cm.  Verbs has a very specific meaning, which gets lost if we start referring to everything as 'verbs'.  It's bad enough that we're stuck with 'drivers/infiniband' and 'rdma', such that 'infiniband' also means ethernet and rdma means nothing. 

> +
> +enum uverbs_attr_type {
> +	UVERBS_ATTR_TYPE_PTR_IN,
> +	UVERBS_ATTR_TYPE_PTR_OUT,
> +	UVERBS_ATTR_TYPE_IDR,
> +	UVERBS_ATTR_TYPE_FD,
> +};
> +
> +enum uverbs_idr_access {
> +	UVERBS_IDR_ACCESS_READ,
> +	UVERBS_IDR_ACCESS_WRITE,
> +	UVERBS_IDR_ACCESS_NEW,
> +	UVERBS_IDR_ACCESS_DESTROY
> +};
> +
> +struct uverbs_attr_spec {
> +	u16				len;
> +	enum uverbs_attr_type		type;
> +	struct {
> +		u16			obj_type;
> +		u8			access;

Is access intended to be an enum uverbs_idr_access value?

> +	} obj;

I would remove (flatten) the substructure and re-order the fields for better alignment.

> +};
> +
> +struct uverbs_attr_group_spec {
> +	struct uverbs_attr_spec		*attrs;
> +	size_t				num_attrs;
> +};
> +
> +struct uverbs_action_spec {
> +	const struct uverbs_attr_group_spec		**attr_groups;
> +	/* if > 0 -> validator, otherwise, error */

? not sure what this comment means

> +	int (*dist)(__u16 *attr_id, void *priv);

What does 'dist' stand for?

> +	void						*priv;
> +	size_t						num_groups;
> +};
> +
> +struct uverbs_attr_array;
> +struct ib_uverbs_file;
> +
> +struct uverbs_action {
> +	struct uverbs_action_spec spec;
> +	void *priv;
> +	int (*handler)(struct ib_device *ib_dev, struct ib_uverbs_file
> *ufile,
> +		       struct uverbs_attr_array *ctx, size_t num, void
> *priv);
> +};
> +
> +struct uverbs_type_alloc_action;
> +typedef void (*free_type)(const struct uverbs_type_alloc_action
> *uobject_type,
> +			  struct ib_uobject *uobject);
> +
> +struct uverbs_type_alloc_action {
> +	enum uverbs_attr_type		type;
> +	int				order;

I think this is being used as destroy order, in which case I would rename it to clarify the intent.  Though I'd prefer we come up with a more efficient destruction mechanism than the repeated nested looping.

> +	size_t				obj_size;

This can be alloc_fn

> +	free_type			free_fn;
> +	struct {
> +		const struct file_operations	*fops;
> +		const char			*name;
> +		int				flags;
> +	} fd;
> +};
> +
> +struct uverbs_type_actions_group {
> +	size_t					num_actions;
> +	const struct uverbs_action		**actions;
> +};
> +
> +struct uverbs_type {
> +	size_t					num_groups;
> +	const struct uverbs_type_actions_group	**action_groups;
> +	const struct uverbs_type_alloc_action	*alloc;
> +	int (*dist)(__u16 *action_id, void *priv);
> +	void					*priv;
> +};
> +
> +struct uverbs_types {
> +	size_t					num_types;
> +	const struct uverbs_type		**types;
> +};
> +
> +struct uverbs_types_group {
> +	const struct uverbs_types		**type_groups;
> +	size_t					num_groups;
> +	int (*dist)(__u16 *type_id, void *priv);
> +	void					*priv;
> +};
> +
> +/* =================================================
> + *              Parsing infrastructure
> + * =================================================
> + */
> +
> +struct uverbs_ptr_attr {
> +	void	* __user ptr;
> +	__u16		len;
> +};
> +
> +struct uverbs_fd_attr {
> +	int		fd;
> +};
> +
> +struct uverbs_uobj_attr {
> +	/*  idr handle */
> +	__u32	idr;
> +};
> +
> +struct uverbs_obj_attr {
> +	/* pointer to the kernel descriptor -> type, access, etc */
> +	const struct uverbs_attr_spec *val;
> +	struct ib_uverbs_attr __user	*uattr;
> +	const struct uverbs_type_alloc_action	*type;
> +	struct ib_uobject		*uobject;
> +	union {
> +		struct uverbs_fd_attr		fd;
> +		struct uverbs_uobj_attr		uobj;
> +	};
> +};
> +
> +struct uverbs_attr {
> +	bool valid;
> +	union {
> +		struct uverbs_ptr_attr	cmd_attr;
> +		struct uverbs_obj_attr	obj_attr;
> +	};
> +};

It's odd to have a union that's part of a structure without some field to indicate which union field is accessible.

> +
> +/* output of one validator */
> +struct uverbs_attr_array {
> +	size_t num_attrs;
> +	/* arrays of attrubytes, index is the id i.e SEND_CQ */
> +	struct uverbs_attr *attrs;
> +};
> +
> +/* =================================================
> + *              Types infrastructure
> + * =================================================
> + */
> +
> +int ib_uverbs_uobject_type_add(struct list_head	*head,
> +			       void (*free)(struct uverbs_uobject_type *type,
> +					    struct ib_uobject *uobject,
> +					    struct ib_ucontext *ucontext),
> +			       uint16_t	obj_type);
> +void ib_uverbs_uobject_types_remove(struct ib_device *ib_dev);
> +
> +#endif
> --
> 2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Matan Barak Oct. 31, 2016, 10:58 p.m. UTC | #2
On Sun, Oct 30, 2016 at 9:28 PM, Hefty, Sean <sean.hefty@intel.com> wrote:
> I found this patch very hard to follow.  This was in part due to the output of the patch command itself, but also because there lacked sufficient documentation on what the new data structures were for and the terms being used.  As a result, I had to bounce around the patch to figure things out, adding comments as I went along, until I finally just gave up trying to read it.

Actually, there are some helpful slides in the OFVWG presentations. I
guess it would be best to clarify the model in the commit message.

>
>> The new ioctl infrastructure supports driver specific objects.
>> Each such object type has a free function, allocation size and an
>
> You can replace the allocation size with an alloc function, to pair with the free call.  Then the object can be initialized by the user.
>

I had thought about that, but the user could initialize its part of
the object in the function handler. It can't allocate the object as we
need it in order to allocate an IDR entry and co. The assumption here
is that the "unlock" stage can't fail.

>> order of destruction. This information is embedded in the same
>> table describing the various action allowed on the object, similarly
>> to object oriented programming.
>>
>> When a ucontext is created, a new list is created in this ib_ucontext.
>> This list contains all objects created under this ib_ucontext.
>> When a ib_ucontext is destroyed, we traverse this list several time
>> destroying the various objects by the order mentioned in the object
>> type description. If few object types have the same destruction order,
>> they are destroyed in an order opposite to their creation order.
>
> Could we simply walk the list backwards, destroying all objects with a reference count of 1 - repeat if necessary?  Basically avoid complex rules for this.
>

That's problematic in the MW case. A MW could be disassociated from
its MR by a remote peer. The kernel can't follow that.

> In fact, it would be great if we could just cleanup the list in the reverse order that items were created.  Maybe this requires supporting a pre-cleanup handler, so that the driver can pluck items out of the list that may need to be destroyed out of order.
>

So that's essentially one layer of ordering. Why do you consider a
driver iterating over all objects simpler than this model?

>> Adding an object is done in two parts.
>> First, an object is allocated and added to IDR/fd table. Then, the
>> command's handlers (in downstream patches) could work on this object
>> and fill in its required details.
>> After a successful command, ib_uverbs_uobject_enable is called and
>> this user objects becomes ucontext visible.
>
> If you have a way to mark that an object is used for exclusive access, you may be able to use that instead of introducing a new variable.  (I.e. acquire the object's write lock).  I think we want to make an effort to minimize the size of the kernel structure needed to track every user space object (within reason).
>

I didn't really follow. A command attribute states the nature of the
locking (for example, in MODIFY_QP the QP could be exclusively locked,
but in QUERY_QP it's only locked for reading). I don't want to really
grab a lock, as if I were I could face a dead-lock (user-space could
pass parameters in a colliding order), It could be solved by sorting
the handles, but that would degrade performance without a good reasob.

>> Removing an uboject is done by calling ib_uverbs_uobject_remove.
>>
>> We should make sure IDR (per-device) and list (per-ucontext) could
>> be accessed concurrently without corrupting them.
>>
>> Signed-off-by: Matan Barak <matanb@mellanox.com>
>> Signed-off-by: Haggai Eran <haggaie@mellanox.com>
>> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
>> ---
>
> As a general comment, I do have concerns that the resulting generalized parsing of everything will negatively impact performance for operations that do have to transition into the kernel.  Not all devices offload all operations to user space.  Plus the resulting code is extremely difficult to read and non-trivial to use.  It's equivalent to reading C++ code that has 4 layers of inheritance with overrides to basic operators...

There are two parts here. I think the handlers themselves are simpler,
easier to read and less error-prone. They contain less code
duplications. The macro based define language explicitly declare all
attributes, their types, size, etc.
The model here is a bit more complex as we want to achieve both code
resue and add/override of new types/actions/attributes.


>
> Pre and post operators per command that can do straightforward validation seem like a better option.
>
>

I think that would duplicate a lot of code and will be more
error-prone than one infrastrucutre that automates all that work for
you.

>>  drivers/infiniband/core/Makefile      |   3 +-
>>  drivers/infiniband/core/device.c      |   1 +
>>  drivers/infiniband/core/rdma_core.c   | 489
>> ++++++++++++++++++++++++++++++++++
>>  drivers/infiniband/core/rdma_core.h   |  75 ++++++
>>  drivers/infiniband/core/uverbs.h      |   1 +
>>  drivers/infiniband/core/uverbs_main.c |   2 +-
>>  include/rdma/ib_verbs.h               |  28 +-
>>  include/rdma/uverbs_ioctl.h           | 195 ++++++++++++++
>>  8 files changed, 789 insertions(+), 5 deletions(-)
>>  create mode 100644 drivers/infiniband/core/rdma_core.c
>>  create mode 100644 drivers/infiniband/core/rdma_core.h
>>  create mode 100644 include/rdma/uverbs_ioctl.h
>>
>> diff --git a/drivers/infiniband/core/Makefile
>> b/drivers/infiniband/core/Makefile
>> index edaae9f..1819623 100644
>> --- a/drivers/infiniband/core/Makefile
>> +++ b/drivers/infiniband/core/Makefile
>> @@ -28,4 +28,5 @@ ib_umad-y :=                        user_mad.o
>>
>>  ib_ucm-y :=                  ucm.o
>>
>> -ib_uverbs-y :=                       uverbs_main.o uverbs_cmd.o
>> uverbs_marshall.o
>> +ib_uverbs-y :=                       uverbs_main.o uverbs_cmd.o
>> uverbs_marshall.o \
>> +                             rdma_core.o
>> diff --git a/drivers/infiniband/core/device.c
>> b/drivers/infiniband/core/device.c
>> index c3b68f5..43994b1 100644
>> --- a/drivers/infiniband/core/device.c
>> +++ b/drivers/infiniband/core/device.c
>> @@ -243,6 +243,7 @@ struct ib_device *ib_alloc_device(size_t size)
>>       spin_lock_init(&device->client_data_lock);
>>       INIT_LIST_HEAD(&device->client_data_list);
>>       INIT_LIST_HEAD(&device->port_list);
>> +     INIT_LIST_HEAD(&device->type_list);
>>
>>       return device;
>>  }
>> diff --git a/drivers/infiniband/core/rdma_core.c
>> b/drivers/infiniband/core/rdma_core.c
>> new file mode 100644
>> index 0000000..337abc2
>> --- /dev/null
>> +++ b/drivers/infiniband/core/rdma_core.c
>> @@ -0,0 +1,489 @@
>> +/*
>> + * Copyright (c) 2016, Mellanox Technologies inc.  All rights
>> reserved.
>> + *
>> + * This software is available to you under a choice of one of two
>> + * licenses.  You may choose to be licensed under the terms of the GNU
>> + * General Public License (GPL) Version 2, available from the file
>> + * COPYING in the main directory of this source tree, or the
>> + * OpenIB.org BSD license below:
>> + *
>> + *     Redistribution and use in source and binary forms, with or
>> + *     without modification, are permitted provided that the following
>> + *     conditions are met:
>> + *
>> + *      - Redistributions of source code must retain the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer.
>> + *
>> + *      - Redistributions in binary form must reproduce the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer in the documentation and/or other materials
>> + *        provided with the distribution.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + */
>> +
>> +#include <linux/file.h>
>> +#include <linux/anon_inodes.h>
>> +#include <rdma/ib_verbs.h>
>> +#include "uverbs.h"
>> +#include "rdma_core.h"
>> +#include <rdma/uverbs_ioctl.h>
>> +
>> +const struct uverbs_type *uverbs_get_type(const struct ib_device
>> *ibdev,
>> +                                       uint16_t type)
>> +{
>> +     const struct uverbs_types_group *groups = ibdev->types_group;
>> +     const struct uverbs_types *types;
>> +     int ret = groups->dist(&type, groups->priv);
>> +
>> +     if (ret >= groups->num_groups)
>> +             return NULL;
>> +
>> +     types = groups->type_groups[ret];
>> +
>> +     if (type >= types->num_types)
>> +             return NULL;
>> +
>> +     return types->types[type];
>> +}
>> +
>> +static int uverbs_lock_object(struct ib_uobject *uobj,
>> +                           enum uverbs_idr_access access)
>> +{
>> +     if (access == UVERBS_IDR_ACCESS_READ)
>> +             return down_read_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
>> +
>> +     /* lock is either WRITE or DESTROY - should be exclusive */
>> +     return down_write_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
>
> This function could take the lock type directly (read or write), versus inferring it based on some other access type.
>

We can, but since we use these enums in the attribute specifications,
I thought it could be more convinient.

>> +}
>> +
>> +static struct ib_uobject *get_uobj(int id, struct ib_ucontext
>> *context)
>> +{
>> +     struct ib_uobject *uobj;
>> +
>> +     rcu_read_lock();
>> +     uobj = idr_find(&context->device->idr, id);
>> +     if (uobj && uobj->live) {
>> +             if (uobj->context != context)
>> +                     uobj = NULL;
>> +     }
>> +     rcu_read_unlock();
>> +
>> +     return uobj;
>> +}
>> +
>> +struct ib_ucontext_lock {
>> +     struct kref  ref;
>> +     /* locking the uobjects_list */
>> +     struct mutex lock;
>> +};
>> +
>> +static void init_uobjects_list_lock(struct ib_ucontext_lock *lock)
>> +{
>> +     mutex_init(&lock->lock);
>> +     kref_init(&lock->ref);
>> +}
>> +
>> +static void release_uobjects_list_lock(struct kref *ref)
>> +{
>> +     struct ib_ucontext_lock *lock = container_of(ref,
>> +                                                  struct ib_ucontext_lock,
>> +                                                  ref);
>> +
>> +     kfree(lock);
>> +}
>> +
>> +static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
>> +                   struct ib_ucontext *context)
>> +{
>> +     init_rwsem(&uobj->usecnt);
>> +     uobj->user_handle = user_handle;
>> +     uobj->context     = context;
>> +     uobj->live        = 0;
>> +}
>> +
>> +static int add_uobj(struct ib_uobject *uobj)
>> +{
>> +     int ret;
>> +
>> +     idr_preload(GFP_KERNEL);
>> +     spin_lock(&uobj->context->device->idr_lock);
>> +
>> +     ret = idr_alloc(&uobj->context->device->idr, uobj, 0, 0,
>> GFP_NOWAIT);
>> +     if (ret >= 0)
>> +             uobj->id = ret;
>> +
>> +     spin_unlock(&uobj->context->device->idr_lock);
>> +     idr_preload_end();
>> +
>> +     return ret < 0 ? ret : 0;
>> +}
>> +
>> +static void remove_uobj(struct ib_uobject *uobj)
>> +{
>> +     spin_lock(&uobj->context->device->idr_lock);
>> +     idr_remove(&uobj->context->device->idr, uobj->id);
>> +     spin_unlock(&uobj->context->device->idr_lock);
>> +}
>> +
>> +static void put_uobj(struct ib_uobject *uobj)
>> +{
>> +     kfree_rcu(uobj, rcu);
>> +}
>> +
>> +static struct ib_uobject *get_uobject_from_context(struct ib_ucontext
>> *ucontext,
>> +                                                const struct
>> uverbs_type_alloc_action *type,
>> +                                                u32 idr,
>> +                                                enum uverbs_idr_access access)
>> +{
>> +     struct ib_uobject *uobj;
>> +     int ret;
>> +
>> +     rcu_read_lock();
>> +     uobj = get_uobj(idr, ucontext);
>> +     if (!uobj)
>> +             goto free;
>> +
>> +     if (uobj->type != type) {
>> +             uobj = NULL;
>> +             goto free;
>> +     }
>> +
>> +     ret = uverbs_lock_object(uobj, access);
>> +     if (ret)
>> +             uobj = ERR_PTR(ret);
>> +free:
>> +     rcu_read_unlock();
>> +     return uobj;
>> +
>> +     return NULL;
>> +}
>> +
>> +static int ib_uverbs_uobject_add(struct ib_uobject *uobject,
>> +                              const struct uverbs_type_alloc_action
>> *uobject_type)
>> +{
>> +     uobject->type = uobject_type;
>> +     return add_uobj(uobject);
>> +}
>> +
>> +struct ib_uobject *uverbs_get_type_from_idr(const struct
>> uverbs_type_alloc_action *type,
>> +                                         struct ib_ucontext *ucontext,
>> +                                         enum uverbs_idr_access access,
>> +                                         uint32_t idr)
>> +{
>> +     struct ib_uobject *uobj;
>> +     int ret;
>> +
>> +     if (access == UVERBS_IDR_ACCESS_NEW) {
>> +             uobj = kmalloc(type->obj_size, GFP_KERNEL);
>> +             if (!uobj)
>> +                     return ERR_PTR(-ENOMEM);
>> +
>> +             init_uobj(uobj, 0, ucontext);
>> +
>> +             /* lock idr */
>
> Command to lock idr, but no lock is obtained.
>

ib_uverbs_uobject_add calls add_uobj which locks the IDR.

>> +             ret = ib_uverbs_uobject_add(uobj, type);
>> +             if (ret) {
>> +                     kfree(uobj);
>> +                     return ERR_PTR(ret);
>> +             }
>> +
>> +     } else {
>> +             uobj = get_uobject_from_context(ucontext, type, idr,
>> +                                             access);
>> +
>> +             if (!uobj)
>> +                     return ERR_PTR(-ENOENT);
>> +     }
>> +
>> +     return uobj;
>> +}
>> +
>> +struct ib_uobject *uverbs_get_type_from_fd(const struct
>> uverbs_type_alloc_action *type,
>> +                                        struct ib_ucontext *ucontext,
>> +                                        enum uverbs_idr_access access,
>> +                                        int fd)
>> +{
>> +     if (access == UVERBS_IDR_ACCESS_NEW) {
>> +             int _fd;
>> +             struct ib_uobject *uobj = NULL;
>> +             struct file *filp;
>> +
>> +             _fd = get_unused_fd_flags(O_CLOEXEC);
>> +             if (_fd < 0 || WARN_ON(type->obj_size < sizeof(struct
>> ib_uobject)))
>> +                     return ERR_PTR(_fd);
>> +
>> +             uobj = kmalloc(type->obj_size, GFP_KERNEL);
>> +             init_uobj(uobj, 0, ucontext);
>> +
>> +             if (!uobj)
>> +                     return ERR_PTR(-ENOMEM);
>> +
>> +             filp = anon_inode_getfile(type->fd.name, type->fd.fops,
>> +                                       uobj + 1, type->fd.flags);
>> +             if (IS_ERR(filp)) {
>> +                     put_unused_fd(_fd);
>> +                     kfree(uobj);
>> +                     return (void *)filp;
>> +             }
>> +
>> +             uobj->type = type;
>> +             uobj->id = _fd;
>> +             uobj->object = filp;
>> +
>> +             return uobj;
>> +     } else if (access == UVERBS_IDR_ACCESS_READ) {
>> +             struct file *f = fget(fd);
>> +             struct ib_uobject *uobject;
>> +
>> +             if (!f)
>> +                     return ERR_PTR(-EBADF);
>> +
>> +             uobject = f->private_data - sizeof(struct ib_uobject);
>> +             if (f->f_op != type->fd.fops ||
>> +                 !uobject->live) {
>> +                     fput(f);
>> +                     return ERR_PTR(-EBADF);
>> +             }
>> +
>> +             /*
>> +              * No need to protect it with a ref count, as fget
>> increases
>> +              * f_count.
>> +              */
>> +             return uobject;
>> +     } else {
>> +             return ERR_PTR(-EOPNOTSUPP);
>> +     }
>> +}
>> +
>> +static void ib_uverbs_uobject_enable(struct ib_uobject *uobject)
>> +{
>> +     mutex_lock(&uobject->context->uobjects_lock->lock);
>> +     list_add(&uobject->list, &uobject->context->uobjects);
>> +     mutex_unlock(&uobject->context->uobjects_lock->lock);
>
> Why not just insert the object into the list on creation?
>
>> +     uobject->live = 1;
>
> See my comments above on removing the live field.
>

Seems that the list could suffice, but I'll look into that.

>> +}
>> +
>> +static void ib_uverbs_uobject_remove(struct ib_uobject *uobject, bool
>> lock)
>> +{
>> +     /*
>> +      * Calling remove requires exclusive access, so it's not possible
>> +      * another thread will use our object.
>> +      */
>> +     uobject->live = 0;
>> +     uobject->type->free_fn(uobject->type, uobject);
>> +     if (lock)
>> +             mutex_lock(&uobject->context->uobjects_lock->lock);
>> +     list_del(&uobject->list);
>> +     if (lock)
>> +             mutex_unlock(&uobject->context->uobjects_lock->lock);
>> +     remove_uobj(uobject);
>> +     put_uobj(uobject);
>> +}
>> +
>> +static void uverbs_unlock_idr(struct ib_uobject *uobj,
>> +                           enum uverbs_idr_access access,
>> +                           bool success)
>> +{
>> +     switch (access) {
>> +     case UVERBS_IDR_ACCESS_READ:
>> +             up_read(&uobj->usecnt);
>> +             break;
>> +     case UVERBS_IDR_ACCESS_NEW:
>> +             if (success) {
>> +                     ib_uverbs_uobject_enable(uobj);
>> +             } else {
>> +                     remove_uobj(uobj);
>> +                     put_uobj(uobj);
>> +             }
>> +             break;
>> +     case UVERBS_IDR_ACCESS_WRITE:
>> +             up_write(&uobj->usecnt);
>> +             break;
>> +     case UVERBS_IDR_ACCESS_DESTROY:
>> +             if (success)
>> +                     ib_uverbs_uobject_remove(uobj, true);
>> +             else
>> +                     up_write(&uobj->usecnt);
>> +             break;
>> +     }
>> +}
>> +
>> +static void uverbs_unlock_fd(struct ib_uobject *uobj,
>> +                          enum uverbs_idr_access access,
>> +                          bool success)
>> +{
>> +     struct file *filp = uobj->object;
>> +
>> +     if (access == UVERBS_IDR_ACCESS_NEW) {
>> +             if (success) {
>> +                     kref_get(&uobj->context->ufile->ref);
>> +                     uobj->uobjects_lock = uobj->context->uobjects_lock;
>> +                     kref_get(&uobj->uobjects_lock->ref);
>> +                     ib_uverbs_uobject_enable(uobj);
>> +                     fd_install(uobj->id, uobj->object);
>
> I don't get this.  The function is unlocking something, but there are calls to get krefs?
>

Before invoking the user's callback, we're first locking all objects
and afterwards we're unlocking them. When we need to create a new
object, the lock becomes object creation and the unlock could become
(assuming the user's callback succeeded) enabling this new object.
When you add a new object (or fd in this case), we take a reference
count to both the uverbs_file and the locking context.

>> +             } else {
>> +                     fput(uobj->object);
>> +                     put_unused_fd(uobj->id);
>> +                     kfree(uobj);
>> +             }
>> +     } else {
>> +             fput(filp);
>> +     }
>> +}
>> +
>> +void uverbs_unlock_object(struct ib_uobject *uobj,
>> +                       enum uverbs_idr_access access,
>> +                       bool success)
>> +{
>> +     if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
>> +             uverbs_unlock_idr(uobj, access, success);
>> +     else if (uobj->type->type == UVERBS_ATTR_TYPE_FD)
>> +             uverbs_unlock_fd(uobj, access, success);
>> +     else
>> +             WARN_ON(true);
>> +}
>> +
>> +static void ib_uverbs_remove_fd(struct ib_uobject *uobject)
>> +{
>> +     /*
>> +      * user should release the uobject in the release
>> +      * callback.
>> +      */
>> +     if (uobject->live) {
>> +             uobject->live = 0;
>> +             list_del(&uobject->list);
>> +             uobject->type->free_fn(uobject->type, uobject);
>> +             kref_put(&uobject->context->ufile->ref,
>> ib_uverbs_release_file);
>> +             uobject->context = NULL;
>> +     }
>> +}
>> +
>> +void ib_uverbs_close_fd(struct file *f)
>> +{
>> +     struct ib_uobject *uobject = f->private_data - sizeof(struct
>> ib_uobject);
>> +
>> +     mutex_lock(&uobject->uobjects_lock->lock);
>> +     if (uobject->live) {
>> +             uobject->live = 0;
>> +             list_del(&uobject->list);
>> +             kref_put(&uobject->context->ufile->ref,
>> ib_uverbs_release_file);
>> +             uobject->context = NULL;
>> +     }
>> +     mutex_unlock(&uobject->uobjects_lock->lock);
>> +     kref_put(&uobject->uobjects_lock->ref,
>> release_uobjects_list_lock);
>> +}
>> +
>> +void ib_uverbs_cleanup_fd(void *private_data)
>> +{
>> +     struct ib_uboject *uobject = private_data - sizeof(struct
>> ib_uobject);
>> +
>> +     kfree(uobject);
>> +}
>> +
>> +void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
>> +                        size_t num,
>> +                        const struct uverbs_action_spec *spec,
>> +                        bool success)
>> +{
>> +     unsigned int i;
>> +
>> +     for (i = 0; i < num; i++) {
>> +             struct uverbs_attr_array *attr_spec_array = &attr_array[i];
>> +             const struct uverbs_attr_group_spec *group_spec =
>> +                     spec->attr_groups[i];
>> +             unsigned int j;
>> +
>> +             for (j = 0; j < attr_spec_array->num_attrs; j++) {
>> +                     struct uverbs_attr *attr = &attr_spec_array-
>> >attrs[j];
>> +                     struct uverbs_attr_spec *spec = &group_spec-
>> >attrs[j];
>> +
>> +                     if (!attr->valid)
>> +                             continue;
>> +
>> +                     if (spec->type == UVERBS_ATTR_TYPE_IDR ||
>> +                         spec->type == UVERBS_ATTR_TYPE_FD)
>> +                             /*
>> +                              * refcounts should be handled at the object
>> +                              * level and not at the uobject level.
>> +                              */
>> +                             uverbs_unlock_object(attr->obj_attr.uobject,
>> +                                                  spec->obj.access, success);
>> +             }
>> +     }
>> +}
>> +
>> +static unsigned int get_type_orders(const struct uverbs_types_group
>> *types_group)
>> +{
>> +     unsigned int i;
>> +     unsigned int max = 0;
>> +
>> +     for (i = 0; i < types_group->num_groups; i++) {
>> +             unsigned int j;
>> +             const struct uverbs_types *types = types_group-
>> >type_groups[i];
>> +
>> +             for (j = 0; j < types->num_types; j++) {
>> +                     if (!types->types[j] || !types->types[j]->alloc)
>> +                             continue;
>> +                     if (types->types[j]->alloc->order > max)
>> +                             max = types->types[j]->alloc->order;
>> +             }
>> +     }
>> +
>> +     return max;
>> +}
>> +
>> +void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext
>> *ucontext,
>> +                                          const struct uverbs_types_group
>> *types_group)
>> +{
>> +     unsigned int num_orders = get_type_orders(types_group);
>> +     unsigned int i;
>> +
>> +     for (i = 0; i <= num_orders; i++) {
>> +             struct ib_uobject *obj, *next_obj;
>> +
>> +             /*
>> +              * No need to take lock here, as cleanup should be called
>> +              * after all commands finished executing. Newly executed
>> +              * commands should fail.
>> +              */
>> +             mutex_lock(&ucontext->uobjects_lock->lock);
>
> It's really confusing to see a comment about 'no need to take lock' immediately followed by a call to lock.
>

Yeah :) That was before adding the fd. I'll delete the comment.

>> +             list_for_each_entry_safe(obj, next_obj, &ucontext-
>> >uobjects,
>> +                                      list)
>> +                     if (obj->type->order == i) {
>> +                             if (obj->type->type == UVERBS_ATTR_TYPE_IDR)
>> +                                     ib_uverbs_uobject_remove(obj, false);
>> +                             else
>> +                                     ib_uverbs_remove_fd(obj);
>> +                     }
>> +             mutex_unlock(&ucontext->uobjects_lock->lock);
>> +     }
>> +     kref_put(&ucontext->uobjects_lock->ref,
>> release_uobjects_list_lock);
>> +}
>> +
>> +int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext
>> *ucontext)
>
> Please work on the function names.  This is horrendously long and still doesn't help describe what it does.
>

This just initialized the types part of the ucontext. Any suggestions?

>> +{
>> +     ucontext->uobjects_lock = kmalloc(sizeof(*ucontext-
>> >uobjects_lock),
>> +                                       GFP_KERNEL);
>> +     if (!ucontext->uobjects_lock)
>> +             return -ENOMEM;
>> +
>> +     init_uobjects_list_lock(ucontext->uobjects_lock);
>> +     INIT_LIST_HEAD(&ucontext->uobjects);
>> +
>> +     return 0;
>> +}
>> +
>> +void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext
>> *ucontext)
>> +{
>> +     kfree(ucontext->uobjects_lock);
>> +}
>
> No need to wrap a call to 'free'.
>

In order to abstract away the ucontext type data structure.

>> +
>> diff --git a/drivers/infiniband/core/rdma_core.h
>> b/drivers/infiniband/core/rdma_core.h
>> new file mode 100644
>> index 0000000..8990115
>> --- /dev/null
>> +++ b/drivers/infiniband/core/rdma_core.h
>> @@ -0,0 +1,75 @@
>> +/*
>> + * Copyright (c) 2005 Topspin Communications.  All rights reserved.
>> + * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
>> + * Copyright (c) 2005-2016 Mellanox Technologies. All rights reserved.
>> + * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
>> + * Copyright (c) 2005 PathScale, Inc. All rights reserved.
>> + *
>> + * This software is available to you under a choice of one of two
>> + * licenses.  You may choose to be licensed under the terms of the GNU
>> + * General Public License (GPL) Version 2, available from the file
>> + * COPYING in the main directory of this source tree, or the
>> + * OpenIB.org BSD license below:
>> + *
>> + *     Redistribution and use in source and binary forms, with or
>> + *     without modification, are permitted provided that the following
>> + *     conditions are met:
>> + *
>> + *      - Redistributions of source code must retain the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer.
>> + *
>> + *      - Redistributions in binary form must reproduce the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer in the documentation and/or other materials
>> + *        provided with the distribution.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + */
>> +
>> +#ifndef UOBJECT_H
>> +#define UOBJECT_H
>> +
>> +#include <linux/idr.h>
>> +#include <rdma/uverbs_ioctl.h>
>> +#include <rdma/ib_verbs.h>
>> +#include <linux/mutex.h>
>> +
>> +const struct uverbs_type *uverbs_get_type(const struct ib_device
>> *ibdev,
>> +                                       uint16_t type);
>> +struct ib_uobject *uverbs_get_type_from_idr(const struct
>> uverbs_type_alloc_action *type,
>> +                                         struct ib_ucontext *ucontext,
>> +                                         enum uverbs_idr_access access,
>> +                                         uint32_t idr);
>> +struct ib_uobject *uverbs_get_type_from_fd(const struct
>> uverbs_type_alloc_action *type,
>> +                                        struct ib_ucontext *ucontext,
>> +                                        enum uverbs_idr_access access,
>> +                                        int fd);
>> +void uverbs_unlock_object(struct ib_uobject *uobj,
>> +                       enum uverbs_idr_access access,
>> +                       bool success);
>> +void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
>> +                        size_t num,
>> +                        const struct uverbs_action_spec *spec,
>> +                        bool success);
>> +
>> +void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext
>> *ucontext,
>> +                                          const struct uverbs_types_group
>> *types_group);
>> +int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext
>> *ucontext);
>> +void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext
>> *ucontext);
>> +void ib_uverbs_close_fd(struct file *f);
>> +void ib_uverbs_cleanup_fd(void *private_data);
>> +
>> +static inline void *uverbs_fd_to_priv(struct ib_uobject *uobj)
>> +{
>> +     return uobj + 1;
>> +}
>
> This seems like a rather useless function.
>

Why? The user sholdn't know or care how we put our structs together.

>> +
>> +#endif /* UIDR_H */
>> diff --git a/drivers/infiniband/core/uverbs.h
>> b/drivers/infiniband/core/uverbs.h
>> index 8074705..ae7d4b8 100644
>> --- a/drivers/infiniband/core/uverbs.h
>> +++ b/drivers/infiniband/core/uverbs.h
>> @@ -180,6 +180,7 @@ void idr_remove_uobj(struct ib_uobject *uobj);
>>  struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file
>> *uverbs_file,
>>                                       struct ib_device *ib_dev,
>>                                       int is_async);
>> +void ib_uverbs_release_file(struct kref *ref);
>>  void ib_uverbs_free_async_event_file(struct ib_uverbs_file
>> *uverbs_file);
>>  struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
>>
>> diff --git a/drivers/infiniband/core/uverbs_main.c
>> b/drivers/infiniband/core/uverbs_main.c
>> index f783723..e63357a 100644
>> --- a/drivers/infiniband/core/uverbs_main.c
>> +++ b/drivers/infiniband/core/uverbs_main.c
>> @@ -341,7 +341,7 @@ static void ib_uverbs_comp_dev(struct
>> ib_uverbs_device *dev)
>>       complete(&dev->comp);
>>  }
>>
>> -static void ib_uverbs_release_file(struct kref *ref)
>> +void ib_uverbs_release_file(struct kref *ref)
>>  {
>>       struct ib_uverbs_file *file =
>>               container_of(ref, struct ib_uverbs_file, ref);
>> diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
>> index b5d2075..7240615 100644
>> --- a/include/rdma/ib_verbs.h
>> +++ b/include/rdma/ib_verbs.h
>> @@ -1329,8 +1329,11 @@ struct ib_fmr_attr {
>>
>>  struct ib_umem;
>>
>> +struct ib_ucontext_lock;
>> +
>>  struct ib_ucontext {
>>       struct ib_device       *device;
>> +     struct ib_uverbs_file  *ufile;
>>       struct list_head        pd_list;
>>       struct list_head        mr_list;
>>       struct list_head        mw_list;
>> @@ -1344,6 +1347,10 @@ struct ib_ucontext {
>>       struct list_head        rwq_ind_tbl_list;
>>       int                     closing;
>>
>> +     /* lock for uobjects list */
>> +     struct ib_ucontext_lock *uobjects_lock;
>> +     struct list_head        uobjects;
>> +
>>       struct pid             *tgid;
>>  #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
>>       struct rb_root      umem_tree;
>> @@ -1363,16 +1370,28 @@ struct ib_ucontext {
>>  #endif
>>  };
>>
>> +struct uverbs_object_list;
>> +
>> +#define OLD_ABI_COMPAT
>> +
>>  struct ib_uobject {
>>       u64                     user_handle;    /* handle given to us by userspace
>> */
>>       struct ib_ucontext     *context;        /* associated user context
>> */
>>       void                   *object;         /* containing object */
>>       struct list_head        list;           /* link to context's list */
>> -     int                     id;             /* index into kernel idr */
>> -     struct kref             ref;
>> -     struct rw_semaphore     mutex;          /* protects .live */
>> +     int                     id;             /* index into kernel idr/fd */
>> +#ifdef OLD_ABI_COMPAT
>> +     struct kref             ref;
>> +#endif
>> +     struct rw_semaphore     usecnt;         /* protects exclusive
>> access */
>> +#ifdef OLD_ABI_COMPAT
>> +     struct rw_semaphore     mutex;          /* protects .live */
>> +#endif
>>       struct rcu_head         rcu;            /* kfree_rcu() overhead */
>>       int                     live;
>> +
>> +     const struct uverbs_type_alloc_action *type;
>> +     struct ib_ucontext_lock *uobjects_lock;
>>  };
>>
>>  struct ib_udata {
>> @@ -2101,6 +2120,9 @@ struct ib_device {
>>        */
>>       int (*get_port_immutable)(struct ib_device *, u8, struct
>> ib_port_immutable *);
>>       void (*get_dev_fw_str)(struct ib_device *, char *str, size_t
>> str_len);
>> +     struct list_head type_list;
>> +
>> +     const struct uverbs_types_group *types_group;
>>  };
>>
>>  struct ib_client {
>> diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
>> new file mode 100644
>> index 0000000..2f50045
>> --- /dev/null
>> +++ b/include/rdma/uverbs_ioctl.h
>> @@ -0,0 +1,195 @@
>> +/*
>> + * Copyright (c) 2016, Mellanox Technologies inc.  All rights
>> reserved.
>> + *
>> + * This software is available to you under a choice of one of two
>> + * licenses.  You may choose to be licensed under the terms of the GNU
>> + * General Public License (GPL) Version 2, available from the file
>> + * COPYING in the main directory of this source tree, or the
>> + * OpenIB.org BSD license below:
>> + *
>> + *     Redistribution and use in source and binary forms, with or
>> + *     without modification, are permitted provided that the following
>> + *     conditions are met:
>> + *
>> + *      - Redistributions of source code must retain the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer.
>> + *
>> + *      - Redistributions in binary form must reproduce the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer in the documentation and/or other materials
>> + *        provided with the distribution.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + */
>> +
>> +#ifndef _UVERBS_IOCTL_
>> +#define _UVERBS_IOCTL_
>> +
>> +#include <linux/kernel.h>
>> +
>> +struct uverbs_object_type;
>> +struct ib_ucontext;
>> +struct ib_uobject;
>> +struct ib_device;
>> +struct uverbs_uobject_type;
>> +
>> +/*
>> + * =======================================
>> + *   Verbs action specifications
>> + * =======================================
>> + */
>
> I intentionally used urdma (though condensed to 3 letters that I don't recall atm), rather than uverbs.  This will need to work with non-verbs devices and interfaces -- again, consider how this fits with the rdma cm.  Verbs has a very specific meaning, which gets lost if we start referring to everything as 'verbs'.  It's bad enough that we're stuck with 'drivers/infiniband' and 'rdma', such that 'infiniband' also means ethernet and rdma means nothing.
>

IMHO - let's agree on the concept of this infrastructure. One we
decide its scope, we could generalize it (i.e - ioctl_provider and
ioctl_context) and implement it to rdma-cm as well.

>> +
>> +enum uverbs_attr_type {
>> +     UVERBS_ATTR_TYPE_PTR_IN,
>> +     UVERBS_ATTR_TYPE_PTR_OUT,
>> +     UVERBS_ATTR_TYPE_IDR,
>> +     UVERBS_ATTR_TYPE_FD,
>> +};
>> +
>> +enum uverbs_idr_access {
>> +     UVERBS_IDR_ACCESS_READ,
>> +     UVERBS_IDR_ACCESS_WRITE,
>> +     UVERBS_IDR_ACCESS_NEW,
>> +     UVERBS_IDR_ACCESS_DESTROY
>> +};
>> +
>> +struct uverbs_attr_spec {
>> +     u16                             len;
>> +     enum uverbs_attr_type           type;
>> +     struct {
>> +             u16                     obj_type;
>> +             u8                      access;
>
> Is access intended to be an enum uverbs_idr_access value?
>

Yeah, worth using this enum. Thanks.

>> +     } obj;
>
> I would remove (flatten) the substructure and re-order the fields for better alignment.
>

I noticed there are several places which aren't aliged. It's in my todo list.

>> +};
>> +
>> +struct uverbs_attr_group_spec {
>> +     struct uverbs_attr_spec         *attrs;
>> +     size_t                          num_attrs;
>> +};
>> +
>> +struct uverbs_action_spec {
>> +     const struct uverbs_attr_group_spec             **attr_groups;
>> +     /* if > 0 -> validator, otherwise, error */
>
> ? not sure what this comment means
>
>> +     int (*dist)(__u16 *attr_id, void *priv);
>
> What does 'dist' stand for?
>

dist = distribution function.
It maps the attributes you got from the user-space to your groups. You
could think of each group as a namespace - where its attributes (or
types/actions) starts from zero in the sake of compactness.
So, for example, it gets an attribute 0x8010 and maps to to "group 1"
(provider) and attribute 0x10.

>> +     void                                            *priv;
>> +     size_t                                          num_groups;
>> +};
>> +
>> +struct uverbs_attr_array;
>> +struct ib_uverbs_file;
>> +
>> +struct uverbs_action {
>> +     struct uverbs_action_spec spec;
>> +     void *priv;
>> +     int (*handler)(struct ib_device *ib_dev, struct ib_uverbs_file
>> *ufile,
>> +                    struct uverbs_attr_array *ctx, size_t num, void
>> *priv);
>> +};
>> +
>> +struct uverbs_type_alloc_action;
>> +typedef void (*free_type)(const struct uverbs_type_alloc_action
>> *uobject_type,
>> +                       struct ib_uobject *uobject);
>> +
>> +struct uverbs_type_alloc_action {
>> +     enum uverbs_attr_type           type;
>> +     int                             order;
>
> I think this is being used as destroy order, in which case I would rename it to clarify the intent.  Though I'd prefer we come up with a more efficient destruction mechanism than the repeated nested looping.
>

In one of the earlier revisions I used a sorted list, which was
efficient. I recall that Jason didn't like its complexity and
re-thinking about that - he's right. Most of your types are "order
number" 0 anyway. So you'll probably iterate very few objects in the
next round (in verbs, everything but MRs and PDs).

>> +     size_t                          obj_size;
>
> This can be alloc_fn
>
>> +     free_type                       free_fn;
>> +     struct {
>> +             const struct file_operations    *fops;
>> +             const char                      *name;
>> +             int                             flags;
>> +     } fd;
>> +};
>> +
>> +struct uverbs_type_actions_group {
>> +     size_t                                  num_actions;
>> +     const struct uverbs_action              **actions;
>> +};
>> +
>> +struct uverbs_type {
>> +     size_t                                  num_groups;
>> +     const struct uverbs_type_actions_group  **action_groups;
>> +     const struct uverbs_type_alloc_action   *alloc;
>> +     int (*dist)(__u16 *action_id, void *priv);
>> +     void                                    *priv;
>> +};
>> +
>> +struct uverbs_types {
>> +     size_t                                  num_types;
>> +     const struct uverbs_type                **types;
>> +};
>> +
>> +struct uverbs_types_group {
>> +     const struct uverbs_types               **type_groups;
>> +     size_t                                  num_groups;
>> +     int (*dist)(__u16 *type_id, void *priv);
>> +     void                                    *priv;
>> +};
>> +
>> +/* =================================================
>> + *              Parsing infrastructure
>> + * =================================================
>> + */
>> +
>> +struct uverbs_ptr_attr {
>> +     void    * __user ptr;
>> +     __u16           len;
>> +};
>> +
>> +struct uverbs_fd_attr {
>> +     int             fd;
>> +};
>> +
>> +struct uverbs_uobj_attr {
>> +     /*  idr handle */
>> +     __u32   idr;
>> +};
>> +
>> +struct uverbs_obj_attr {
>> +     /* pointer to the kernel descriptor -> type, access, etc */
>> +     const struct uverbs_attr_spec *val;
>> +     struct ib_uverbs_attr __user    *uattr;
>> +     const struct uverbs_type_alloc_action   *type;
>> +     struct ib_uobject               *uobject;
>> +     union {
>> +             struct uverbs_fd_attr           fd;
>> +             struct uverbs_uobj_attr         uobj;
>> +     };
>> +};
>> +
>> +struct uverbs_attr {
>> +     bool valid;
>> +     union {
>> +             struct uverbs_ptr_attr  cmd_attr;
>> +             struct uverbs_obj_attr  obj_attr;
>> +     };
>> +};
>
> It's odd to have a union that's part of a structure without some field to indicate which union field is accessible.
>

You index this array but the attribute id from the user's callback
funciton. The user should know what's the type of the attribute, as
[s]he declared the specification.

>> +
>> +/* output of one validator */
>> +struct uverbs_attr_array {
>> +     size_t num_attrs;
>> +     /* arrays of attrubytes, index is the id i.e SEND_CQ */
>> +     struct uverbs_attr *attrs;
>> +};
>> +
>> +/* =================================================
>> + *              Types infrastructure
>> + * =================================================
>> + */
>> +
>> +int ib_uverbs_uobject_type_add(struct list_head      *head,
>> +                            void (*free)(struct uverbs_uobject_type *type,
>> +                                         struct ib_uobject *uobject,
>> +                                         struct ib_ucontext *ucontext),
>> +                            uint16_t obj_type);
>> +void ib_uverbs_uobject_types_remove(struct ib_device *ib_dev);
>> +
>> +#endif
>> --
>> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Thanks for taking a look.

Regards,
Matan
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hefty, Sean Nov. 9, 2016, 6 p.m. UTC | #3
PiBJIGhhZCB0aG91Z2h0IGFib3V0IHRoYXQsIGJ1dCB0aGUgdXNlciBjb3VsZCBpbml0aWFsaXpl
IGl0cyBwYXJ0IG9mDQo+IHRoZSBvYmplY3QgaW4gdGhlIGZ1bmN0aW9uIGhhbmRsZXIuIEl0IGNh
bid0IGFsbG9jYXRlIHRoZSBvYmplY3QgYXMgd2UNCj4gbmVlZCBpdCBpbiBvcmRlciB0byBhbGxv
Y2F0ZSBhbiBJRFIgZW50cnkgYW5kIGNvLiBUaGUgYXNzdW1wdGlvbiBoZXJlDQo+IGlzIHRoYXQg
dGhlICJ1bmxvY2siIHN0YWdlIGNhbid0IGZhaWwuDQoNClRoaXMgaXMgY3JlYXRpbmcgYSBnZW5l
cmljIE9PIHR5cGUgb2YgZnJhbWV3b3JrLCBzbyBqdXN0IGFkZCBjb25zdHJ1Y3Rvci9kZXN0cnVj
dG9yIGZ1bmN0aW9ucyBhbmQgaGF2ZSBhbGwgb2JqZWN0cyBpbmhlcml0IGZyb20gYSBiYXNlIGlv
Y3RsIG9iamVjdCBjbGFzcy4NCg0KPiA+IEluIGZhY3QsIGl0IHdvdWxkIGJlIGdyZWF0IGlmIHdl
IGNvdWxkIGp1c3QgY2xlYW51cCB0aGUgbGlzdCBpbiB0aGUNCj4gcmV2ZXJzZSBvcmRlciB0aGF0
IGl0ZW1zIHdlcmUgY3JlYXRlZC4gIE1heWJlIHRoaXMgcmVxdWlyZXMgc3VwcG9ydGluZw0KPiBh
IHByZS1jbGVhbnVwIGhhbmRsZXIsIHNvIHRoYXQgdGhlIGRyaXZlciBjYW4gcGx1Y2sgaXRlbXMg
b3V0IG9mIHRoZQ0KPiBsaXN0IHRoYXQgbWF5IG5lZWQgdG8gYmUgZGVzdHJveWVkIG91dCBvZiBv
cmRlci4NCj4gPg0KPiANCj4gU28gdGhhdCdzIGVzc2VudGlhbGx5IG9uZSBsYXllciBvZiBvcmRl
cmluZy4gV2h5IGRvIHlvdSBjb25zaWRlciBhDQo+IGRyaXZlciBpdGVyYXRpbmcgb3ZlciBhbGwg
b2JqZWN0cyBzaW1wbGVyIHRoYW4gdGhpcyBtb2RlbD8NCg0KVGhpcyBwcm9ibGVtIGlzIGEgdmVy
YnMgc3BlY2lmaWMgaXNzdWUsIGFuZCBvbmUgdGhhdCBvbmx5IGludm9sdmVzIE1XIC4gIFdlIGhh
dmUgcmVmZXJlbmNlIGNvdW50cyB0aGF0IGNhbiBwcm92aWRlIHRoZSBzYW1lIGZ1bmN0aW9uYWxp
dHkuICBJIHdhbnQgdG8gYXZvaWQgdGhlIGFtb3VudCBvZiBtZXRhLWRhdGEgdGhhdCBuZWVkcyB0
byBiZSB1c2VkIHRvIGRlc2NyaWJlIG9iamVjdHMuDQoNCj4gPj4gQWRkaW5nIGFuIG9iamVjdCBp
cyBkb25lIGluIHR3byBwYXJ0cy4NCj4gPj4gRmlyc3QsIGFuIG9iamVjdCBpcyBhbGxvY2F0ZWQg
YW5kIGFkZGVkIHRvIElEUi9mZCB0YWJsZS4gVGhlbiwgdGhlDQo+ID4+IGNvbW1hbmQncyBoYW5k
bGVycyAoaW4gZG93bnN0cmVhbSBwYXRjaGVzKSBjb3VsZCB3b3JrIG9uIHRoaXMgb2JqZWN0DQo+
ID4+IGFuZCBmaWxsIGluIGl0cyByZXF1aXJlZCBkZXRhaWxzLg0KPiA+PiBBZnRlciBhIHN1Y2Nl
c3NmdWwgY29tbWFuZCwgaWJfdXZlcmJzX3VvYmplY3RfZW5hYmxlIGlzIGNhbGxlZCBhbmQNCj4g
Pj4gdGhpcyB1c2VyIG9iamVjdHMgYmVjb21lcyB1Y29udGV4dCB2aXNpYmxlLg0KPiA+DQo+ID4g
SWYgeW91IGhhdmUgYSB3YXkgdG8gbWFyayB0aGF0IGFuIG9iamVjdCBpcyB1c2VkIGZvciBleGNs
dXNpdmUNCj4gYWNjZXNzLCB5b3UgbWF5IGJlIGFibGUgdG8gdXNlIHRoYXQgaW5zdGVhZCBvZiBp
bnRyb2R1Y2luZyBhIG5ldw0KPiB2YXJpYWJsZS4gIChJLmUuIGFjcXVpcmUgdGhlIG9iamVjdCdz
IHdyaXRlIGxvY2spLiAgSSB0aGluayB3ZSB3YW50IHRvDQo+IG1ha2UgYW4gZWZmb3J0IHRvIG1p
bmltaXplIHRoZSBzaXplIG9mIHRoZSBrZXJuZWwgc3RydWN0dXJlIG5lZWRlZCB0bw0KPiB0cmFj
ayBldmVyeSB1c2VyIHNwYWNlIG9iamVjdCAod2l0aGluIHJlYXNvbikuDQo+ID4NCj4gDQo+IEkg
ZGlkbid0IHJlYWxseSBmb2xsb3cuIEEgY29tbWFuZCBhdHRyaWJ1dGUgc3RhdGVzIHRoZSBuYXR1
cmUgb2YgdGhlDQo+IGxvY2tpbmcgKGZvciBleGFtcGxlLCBpbiBNT0RJRllfUVAgdGhlIFFQIGNv
dWxkIGJlIGV4Y2x1c2l2ZWx5IGxvY2tlZCwNCj4gYnV0IGluIFFVRVJZX1FQIGl0J3Mgb25seSBs
b2NrZWQgZm9yIHJlYWRpbmcpLiBJIGRvbid0IHdhbnQgdG8gcmVhbGx5DQo+IGdyYWIgYSBsb2Nr
LCBhcyBpZiBJIHdlcmUgSSBjb3VsZCBmYWNlIGEgZGVhZC1sb2NrICh1c2VyLXNwYWNlIGNvdWxk
DQo+IHBhc3MgcGFyYW1ldGVycyBpbiBhIGNvbGxpZGluZyBvcmRlciksIEl0IGNvdWxkIGJlIHNv
bHZlZCBieSBzb3J0aW5nDQo+IHRoZSBoYW5kbGVzLCBidXQgdGhhdCB3b3VsZCBkZWdyYWRlIHBl
cmZvcm1hbmNlIHdpdGhvdXQgYSBnb29kIHJlYXNvYi4NCg0KSSdtIHN1Z2dlc3RpbmcgdGhhdCB0
aGUgbG9ja2luZyBhdHRyaWJ1dGUgYW5kIGNvbW1hbmQgYmUgc2VwYXJhdGUuICBUaGlzIGFsbG93
cyB0aGUgZnJhbWV3b3JrIHRvIGFjcXVpcmUgdGhlIHByb3BlciB0eXBlIG9mIGxvY2sgaW5kZXBl
bmRlbnQgb2Ygd2hhdCBmdW5jdGlvbiBpdCB3aWxsIGludm9rZS4NCg0KVGhlIGZyYW1ld29yayBk
b2Vzbid0IG5lZWQgdG8gaG9sZCBsb2Nrcy4gIEl0IHNob3VsZCBiZSBhYmxlIHRvIG1hcmsgYWNj
ZXNzIHRvIGFuIG9iamVjdC4gIElmIHRoYXQgYWNjZXNzIGlzIG5vdCBhdmFpbGFibGUsIGl0IGNh
biBhYm9ydC4gIFRoaXMgcHVzaGVzIG1vcmUgY29tcGxleCBzeW5jaHJvbml6YXRpb24gYW5kIHRo
cmVhZCBoYW5kbGluZyB0byB1c2VyIHNwYWNlLg0KDQo+ID4+IFJlbW92aW5nIGFuIHVib2plY3Qg
aXMgZG9uZSBieSBjYWxsaW5nIGliX3V2ZXJic191b2JqZWN0X3JlbW92ZS4NCj4gPj4NCj4gPj4g
V2Ugc2hvdWxkIG1ha2Ugc3VyZSBJRFIgKHBlci1kZXZpY2UpIGFuZCBsaXN0IChwZXItdWNvbnRl
eHQpIGNvdWxkDQo+ID4+IGJlIGFjY2Vzc2VkIGNvbmN1cnJlbnRseSB3aXRob3V0IGNvcnJ1cHRp
bmcgdGhlbS4NCj4gPj4NCj4gPj4gU2lnbmVkLW9mZi1ieTogTWF0YW4gQmFyYWsgPG1hdGFuYkBt
ZWxsYW5veC5jb20+DQo+ID4+IFNpZ25lZC1vZmYtYnk6IEhhZ2dhaSBFcmFuIDxoYWdnYWllQG1l
bGxhbm94LmNvbT4NCj4gPj4gU2lnbmVkLW9mZi1ieTogTGVvbiBSb21hbm92c2t5IDxsZW9ucm9A
bWVsbGFub3guY29tPg0KPiA+PiAtLS0NCj4gPg0KPiA+IEFzIGEgZ2VuZXJhbCBjb21tZW50LCBJ
IGRvIGhhdmUgY29uY2VybnMgdGhhdCB0aGUgcmVzdWx0aW5nDQo+IGdlbmVyYWxpemVkIHBhcnNp
bmcgb2YgZXZlcnl0aGluZyB3aWxsIG5lZ2F0aXZlbHkgaW1wYWN0IHBlcmZvcm1hbmNlDQo+IGZv
ciBvcGVyYXRpb25zIHRoYXQgZG8gaGF2ZSB0byB0cmFuc2l0aW9uIGludG8gdGhlIGtlcm5lbC4g
IE5vdCBhbGwNCj4gZGV2aWNlcyBvZmZsb2FkIGFsbCBvcGVyYXRpb25zIHRvIHVzZXIgc3BhY2Uu
ICBQbHVzIHRoZSByZXN1bHRpbmcgY29kZQ0KPiBpcyBleHRyZW1lbHkgZGlmZmljdWx0IHRvIHJl
YWQgYW5kIG5vbi10cml2aWFsIHRvIHVzZS4gIEl0J3MgZXF1aXZhbGVudA0KPiB0byByZWFkaW5n
IEMrKyBjb2RlIHRoYXQgaGFzIDQgbGF5ZXJzIG9mIGluaGVyaXRhbmNlIHdpdGggb3ZlcnJpZGVz
IHRvDQo+IGJhc2ljIG9wZXJhdG9ycy4uLg0KPiANCj4gVGhlcmUgYXJlIHR3byBwYXJ0cyBoZXJl
LiBJIHRoaW5rIHRoZSBoYW5kbGVycyB0aGVtc2VsdmVzIGFyZSBzaW1wbGVyLA0KPiBlYXNpZXIg
dG8gcmVhZCBhbmQgbGVzcyBlcnJvci1wcm9uZS4gVGhleSBjb250YWluIGxlc3MgY29kZQ0KPiBk
dXBsaWNhdGlvbnMuIFRoZSBtYWNybyBiYXNlZCBkZWZpbmUgbGFuZ3VhZ2UgZXhwbGljaXRseSBk
ZWNsYXJlIGFsbA0KPiBhdHRyaWJ1dGVzLCB0aGVpciB0eXBlcywgc2l6ZSwgZXRjLg0KPiBUaGUg
bW9kZWwgaGVyZSBpcyBhIGJpdCBtb3JlIGNvbXBsZXggYXMgd2Ugd2FudCB0byBhY2hpZXZlIGJv
dGggY29kZQ0KPiByZXN1ZSBhbmQgYWRkL292ZXJyaWRlIG9mIG5ldyB0eXBlcy9hY3Rpb25zL2F0
dHJpYnV0ZXMuDQo+IA0KPiANCj4gPg0KPiA+IFByZSBhbmQgcG9zdCBvcGVyYXRvcnMgcGVyIGNv
bW1hbmQgdGhhdCBjYW4gZG8gc3RyYWlnaHRmb3J3YXJkDQo+IHZhbGlkYXRpb24gc2VlbSBsaWtl
IGEgYmV0dGVyIG9wdGlvbi4NCj4gPg0KPiA+DQo+IA0KPiBJIHRoaW5rIHRoYXQgd291bGQgZHVw
bGljYXRlIGEgbG90IG9mIGNvZGUgYW5kIHdpbGwgYmUgbW9yZQ0KPiBlcnJvci1wcm9uZSB0aGFu
IG9uZSBpbmZyYXN0cnVjdXRyZSB0aGF0IGF1dG9tYXRlcyBhbGwgdGhhdCB3b3JrIGZvcg0KPiB5
b3UuDQoNCkkgdGhpbmsgdGhhdCdzIGEgdG9zcy11cC4gIEVpdGhlciB5b3UgaGF2ZSB0byB3cml0
ZSB0aGUgY29kZSBjb3JyZWN0bHkgb3Igd3JpdGUgdGhlIHJ1bGVzIGNvcnJlY3RseS4gIFJlYWRp
bmcgY29kZSBpcyBzdHJhaWdodGZvcndhcmQsIG1hbnVhbGx5IGNvbnZlcnRpbmcgcnVsZXMgaW50
byBjb2RlIGlzIG5vdC4NCg0KSW4gYW55IGNhc2UsIHRoZSB0d28gYXBwcm9hY2hlcyBhcmUgbm90
IGV4Y2x1c2l2ZS4gIEJ5IGZvcmNpbmcgdGhlIHJ1bGUgbGFuZ3VhZ2UgaW50byB0aGUgZnJhbWV3
b3JrLCBldmVyeXRoaW5nIGlzIGZvcmNlZCB0byBkZWFsIHdpdGggaXQuICBCeSBsZWF2aW5nIGl0
IG91dCwgZWFjaCBpb2N0bCBwcm92aWRlciBjYW4gZGVjaWRlIGlmIHRoZXkgbmVlZCB0aGlzIG9y
IG5vdC4gIElmIHlvdSB3YW50IHZlcmJzIHRvIHByb2Nlc3MgYWxsIGlvY3RsJ3MgdXNpbmcgYSBz
aW5nbGUgcHJlLXZhbGlkYXRpb24gZnVuY3Rpb24gdGhhdCBvcGVyYXRlcyBiYXNlZCBvbiB0aGVz
ZSBydWxlcyB5b3UgY2FuLiAgTm90aGluZyBwcmV2ZW50cyB0aGF0LiAgQnV0IGlvY3RsIHByb3Zp
ZGVycyB0aGF0IHdhbnQgYmV0dGVyIHBlcmZvcm1hbmNlIGNhbiBlbGVjdCBmb3IgYSBtb3JlIHN0
cmFpZ2h0Zm9yd2FyZCB2YWxpZGF0aW9uIG1vZGVsLg0KDQo+ID4+ICBkcml2ZXJzL2luZmluaWJh
bmQvY29yZS9NYWtlZmlsZSAgICAgIHwgICAzICstDQo+ID4+ICBkcml2ZXJzL2luZmluaWJhbmQv
Y29yZS9kZXZpY2UuYyAgICAgIHwgICAxICsNCj4gPj4gIGRyaXZlcnMvaW5maW5pYmFuZC9jb3Jl
L3JkbWFfY29yZS5jICAgfCA0ODkNCj4gPj4gKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr
KysrKw0KPiA+PiAgZHJpdmVycy9pbmZpbmliYW5kL2NvcmUvcmRtYV9jb3JlLmggICB8ICA3NSAr
KysrKysNCj4gPj4gIGRyaXZlcnMvaW5maW5pYmFuZC9jb3JlL3V2ZXJicy5oICAgICAgfCAgIDEg
Kw0KPiA+PiAgZHJpdmVycy9pbmZpbmliYW5kL2NvcmUvdXZlcmJzX21haW4uYyB8ICAgMiArLQ0K
PiA+PiAgaW5jbHVkZS9yZG1hL2liX3ZlcmJzLmggICAgICAgICAgICAgICB8ICAyOCArLQ0KPiA+
PiAgaW5jbHVkZS9yZG1hL3V2ZXJic19pb2N0bC5oICAgICAgICAgICB8IDE5NSArKysrKysrKysr
KysrKw0KPiA+PiAgOCBmaWxlcyBjaGFuZ2VkLCA3ODkgaW5zZXJ0aW9ucygrKSwgNSBkZWxldGlv
bnMoLSkNCj4gPj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2luZmluaWJhbmQvY29yZS9y
ZG1hX2NvcmUuYw0KPiA+PiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvaW5maW5pYmFuZC9j
b3JlL3JkbWFfY29yZS5oDQo+ID4+ICBjcmVhdGUgbW9kZSAxMDA2NDQgaW5jbHVkZS9yZG1hL3V2
ZXJic19pb2N0bC5oDQo+ID4+DQo+ID4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2luZmluaWJhbmQv
Y29yZS9NYWtlZmlsZQ0KPiA+PiBiL2RyaXZlcnMvaW5maW5pYmFuZC9jb3JlL01ha2VmaWxlDQo+
ID4+IGluZGV4IGVkYWFlOWYuLjE4MTk2MjMgMTAwNjQ0DQo+ID4+IC0tLSBhL2RyaXZlcnMvaW5m
aW5pYmFuZC9jb3JlL01ha2VmaWxlDQo+ID4+ICsrKyBiL2RyaXZlcnMvaW5maW5pYmFuZC9jb3Jl
L01ha2VmaWxlDQo+ID4+IEBAIC0yOCw0ICsyOCw1IEBAIGliX3VtYWQteSA6PSAgICAgICAgICAg
ICAgICAgICAgICAgIHVzZXJfbWFkLm8NCj4gPj4NCj4gPj4gIGliX3VjbS15IDo9ICAgICAgICAg
ICAgICAgICAgdWNtLm8NCj4gPj4NCj4gPj4gLWliX3V2ZXJicy15IDo9ICAgICAgICAgICAgICAg
ICAgICAgICB1dmVyYnNfbWFpbi5vIHV2ZXJic19jbWQubw0KPiA+PiB1dmVyYnNfbWFyc2hhbGwu
bw0KPiA+PiAraWJfdXZlcmJzLXkgOj0gICAgICAgICAgICAgICAgICAgICAgIHV2ZXJic19tYWlu
Lm8gdXZlcmJzX2NtZC5vDQo+ID4+IHV2ZXJic19tYXJzaGFsbC5vIFwNCj4gPj4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgcmRtYV9jb3JlLm8NCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZl
cnMvaW5maW5pYmFuZC9jb3JlL2RldmljZS5jDQo+ID4+IGIvZHJpdmVycy9pbmZpbmliYW5kL2Nv
cmUvZGV2aWNlLmMNCj4gPj4gaW5kZXggYzNiNjhmNS4uNDM5OTRiMSAxMDA2NDQNCj4gPj4gLS0t
IGEvZHJpdmVycy9pbmZpbmliYW5kL2NvcmUvZGV2aWNlLmMNCj4gPj4gKysrIGIvZHJpdmVycy9p
bmZpbmliYW5kL2NvcmUvZGV2aWNlLmMNCj4gPj4gQEAgLTI0Myw2ICsyNDMsNyBAQCBzdHJ1Y3Qg
aWJfZGV2aWNlICppYl9hbGxvY19kZXZpY2Uoc2l6ZV90IHNpemUpDQo+ID4+ICAgICAgIHNwaW5f
bG9ja19pbml0KCZkZXZpY2UtPmNsaWVudF9kYXRhX2xvY2spOw0KPiA+PiAgICAgICBJTklUX0xJ
U1RfSEVBRCgmZGV2aWNlLT5jbGllbnRfZGF0YV9saXN0KTsNCj4gPj4gICAgICAgSU5JVF9MSVNU
X0hFQUQoJmRldmljZS0+cG9ydF9saXN0KTsNCj4gPj4gKyAgICAgSU5JVF9MSVNUX0hFQUQoJmRl
dmljZS0+dHlwZV9saXN0KTsNCj4gPj4NCj4gPj4gICAgICAgcmV0dXJuIGRldmljZTsNCj4gPj4g
IH0NCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvaW5maW5pYmFuZC9jb3JlL3JkbWFfY29yZS5j
DQo+ID4+IGIvZHJpdmVycy9pbmZpbmliYW5kL2NvcmUvcmRtYV9jb3JlLmMNCj4gPj4gbmV3IGZp
bGUgbW9kZSAxMDA2NDQNCj4gPj4gaW5kZXggMDAwMDAwMC4uMzM3YWJjMg0KPiA+PiAtLS0gL2Rl
di9udWxsDQo+ID4+ICsrKyBiL2RyaXZlcnMvaW5maW5pYmFuZC9jb3JlL3JkbWFfY29yZS5jDQo+
ID4+IEBAIC0wLDAgKzEsNDg5IEBADQo+ID4+ICsvKg0KPiA+PiArICogQ29weXJpZ2h0IChjKSAy
MDE2LCBNZWxsYW5veCBUZWNobm9sb2dpZXMgaW5jLiAgQWxsIHJpZ2h0cw0KPiA+PiByZXNlcnZl
ZC4NCj4gPj4gKyAqDQo+ID4+ICsgKiBUaGlzIHNvZnR3YXJlIGlzIGF2YWlsYWJsZSB0byB5b3Ug
dW5kZXIgYSBjaG9pY2Ugb2Ygb25lIG9mIHR3bw0KPiA+PiArICogbGljZW5zZXMuICBZb3UgbWF5
IGNob29zZSB0byBiZSBsaWNlbnNlZCB1bmRlciB0aGUgdGVybXMgb2YgdGhlDQo+IEdOVQ0KPiA+
PiArICogR2VuZXJhbCBQdWJsaWMgTGljZW5zZSAoR1BMKSBWZXJzaW9uIDIsIGF2YWlsYWJsZSBm
cm9tIHRoZSBmaWxlDQo+ID4+ICsgKiBDT1BZSU5HIGluIHRoZSBtYWluIGRpcmVjdG9yeSBvZiB0
aGlzIHNvdXJjZSB0cmVlLCBvciB0aGUNCj4gPj4gKyAqIE9wZW5JQi5vcmcgQlNEIGxpY2Vuc2Ug
YmVsb3c6DQo+ID4+ICsgKg0KPiA+PiArICogICAgIFJlZGlzdHJpYnV0aW9uIGFuZCB1c2UgaW4g
c291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3INCj4gPj4gKyAqICAgICB3aXRob3V0IG1v
ZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZQ0KPiBmb2xsb3dpbmcN
Cj4gPj4gKyAqICAgICBjb25kaXRpb25zIGFyZSBtZXQ6DQo+ID4+ICsgKg0KPiA+PiArICogICAg
ICAtIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUN
Cj4gPj4gKyAqICAgICAgICBjb3B5cmlnaHQgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9u
cyBhbmQgdGhlDQo+IGZvbGxvd2luZw0KPiA+PiArICogICAgICAgIGRpc2NsYWltZXIuDQo+ID4+
ICsgKg0KPiA+PiArICogICAgICAtIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0
IHJlcHJvZHVjZSB0aGUgYWJvdmUNCj4gPj4gKyAqICAgICAgICBjb3B5cmlnaHQgbm90aWNlLCB0
aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlDQo+IGZvbGxvd2luZw0KPiA+PiArICogICAg
ICAgIGRpc2NsYWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFs
cw0KPiA+PiArICogICAgICAgIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4NCj4gPj4g
KyAqDQo+ID4+ICsgKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBX
QVJSQU5UWSBPRiBBTlkgS0lORCwNCj4gPj4gKyAqIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVE
SU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUw0KPiBPRg0KPiA+PiArICogTUVS
Q0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQNCj4gPj4g
KyAqIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09Q
WVJJR0hUDQo+IEhPTERFUlMNCj4gPj4gKyAqIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1B
R0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTg0KPiBBTg0KPiA+PiArICogQUNUSU9O
IE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IN
Cj4gSU4NCj4gPj4gKyAqIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBP
UiBPVEhFUiBERUFMSU5HUyBJTiBUSEUNCj4gPj4gKyAqIFNPRlRXQVJFLg0KPiA+PiArICovDQo+
ID4+ICsNCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9maWxlLmg+DQo+ID4+ICsjaW5jbHVkZSA8bGlu
dXgvYW5vbl9pbm9kZXMuaD4NCj4gPj4gKyNpbmNsdWRlIDxyZG1hL2liX3ZlcmJzLmg+DQo+ID4+
ICsjaW5jbHVkZSAidXZlcmJzLmgiDQo+ID4+ICsjaW5jbHVkZSAicmRtYV9jb3JlLmgiDQo+ID4+
ICsjaW5jbHVkZSA8cmRtYS91dmVyYnNfaW9jdGwuaD4NCj4gPj4gKw0KPiA+PiArY29uc3Qgc3Ry
dWN0IHV2ZXJic190eXBlICp1dmVyYnNfZ2V0X3R5cGUoY29uc3Qgc3RydWN0IGliX2RldmljZQ0K
PiA+PiAqaWJkZXYsDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICB1aW50MTZfdCB0eXBlKQ0KPiA+PiArew0KPiA+PiArICAgICBjb25zdCBzdHJ1Y3QgdXZlcmJz
X3R5cGVzX2dyb3VwICpncm91cHMgPSBpYmRldi0+dHlwZXNfZ3JvdXA7DQo+ID4+ICsgICAgIGNv
bnN0IHN0cnVjdCB1dmVyYnNfdHlwZXMgKnR5cGVzOw0KPiA+PiArICAgICBpbnQgcmV0ID0gZ3Jv
dXBzLT5kaXN0KCZ0eXBlLCBncm91cHMtPnByaXYpOw0KPiA+PiArDQo+ID4+ICsgICAgIGlmIChy
ZXQgPj0gZ3JvdXBzLT5udW1fZ3JvdXBzKQ0KPiA+PiArICAgICAgICAgICAgIHJldHVybiBOVUxM
Ow0KPiA+PiArDQo+ID4+ICsgICAgIHR5cGVzID0gZ3JvdXBzLT50eXBlX2dyb3Vwc1tyZXRdOw0K
PiA+PiArDQo+ID4+ICsgICAgIGlmICh0eXBlID49IHR5cGVzLT5udW1fdHlwZXMpDQo+ID4+ICsg
ICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4+ICsNCj4gPj4gKyAgICAgcmV0dXJuIHR5cGVz
LT50eXBlc1t0eXBlXTsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIGludCB1dmVyYnNf
bG9ja19vYmplY3Qoc3RydWN0IGliX3VvYmplY3QgKnVvYmosDQo+ID4+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICBlbnVtIHV2ZXJic19pZHJfYWNjZXNzIGFjY2VzcykNCj4gPj4gK3sNCj4g
Pj4gKyAgICAgaWYgKGFjY2VzcyA9PSBVVkVSQlNfSURSX0FDQ0VTU19SRUFEKQ0KPiA+PiArICAg
ICAgICAgICAgIHJldHVybiBkb3duX3JlYWRfdHJ5bG9jaygmdW9iai0+dXNlY250KSA9PSAxID8g
MCA6IC0NCj4gRUJVU1k7DQo+ID4+ICsNCj4gPj4gKyAgICAgLyogbG9jayBpcyBlaXRoZXIgV1JJ
VEUgb3IgREVTVFJPWSAtIHNob3VsZCBiZSBleGNsdXNpdmUgKi8NCj4gPj4gKyAgICAgcmV0dXJu
IGRvd25fd3JpdGVfdHJ5bG9jaygmdW9iai0+dXNlY250KSA9PSAxID8gMCA6IC1FQlVTWTsNCj4g
Pg0KPiA+IFRoaXMgZnVuY3Rpb24gY291bGQgdGFrZSB0aGUgbG9jayB0eXBlIGRpcmVjdGx5IChy
ZWFkIG9yIHdyaXRlKSwNCj4gdmVyc3VzIGluZmVycmluZyBpdCBiYXNlZCBvbiBzb21lIG90aGVy
IGFjY2VzcyB0eXBlLg0KPiA+DQo+IA0KPiBXZSBjYW4sIGJ1dCBzaW5jZSB3ZSB1c2UgdGhlc2Ug
ZW51bXMgaW4gdGhlIGF0dHJpYnV0ZSBzcGVjaWZpY2F0aW9ucywNCj4gSSB0aG91Z2h0IGl0IGNv
dWxkIGJlIG1vcmUgY29udmluaWVudC4NCj4gDQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gK3N0YXRp
YyBzdHJ1Y3QgaWJfdW9iamVjdCAqZ2V0X3VvYmooaW50IGlkLCBzdHJ1Y3QgaWJfdWNvbnRleHQN
Cj4gPj4gKmNvbnRleHQpDQo+ID4+ICt7DQo+ID4+ICsgICAgIHN0cnVjdCBpYl91b2JqZWN0ICp1
b2JqOw0KPiA+PiArDQo+ID4+ICsgICAgIHJjdV9yZWFkX2xvY2soKTsNCj4gPj4gKyAgICAgdW9i
aiA9IGlkcl9maW5kKCZjb250ZXh0LT5kZXZpY2UtPmlkciwgaWQpOw0KPiA+PiArICAgICBpZiAo
dW9iaiAmJiB1b2JqLT5saXZlKSB7DQo+ID4+ICsgICAgICAgICAgICAgaWYgKHVvYmotPmNvbnRl
eHQgIT0gY29udGV4dCkNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgIHVvYmogPSBOVUxMOw0K
PiA+PiArICAgICB9DQo+ID4+ICsgICAgIHJjdV9yZWFkX3VubG9jaygpOw0KPiA+PiArDQo+ID4+
ICsgICAgIHJldHVybiB1b2JqOw0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtzdHJ1Y3QgaWJfdWNv
bnRleHRfbG9jayB7DQo+ID4+ICsgICAgIHN0cnVjdCBrcmVmICByZWY7DQo+ID4+ICsgICAgIC8q
IGxvY2tpbmcgdGhlIHVvYmplY3RzX2xpc3QgKi8NCj4gPj4gKyAgICAgc3RydWN0IG11dGV4IGxv
Y2s7DQo+ID4+ICt9Ow0KPiA+PiArDQo+ID4+ICtzdGF0aWMgdm9pZCBpbml0X3VvYmplY3RzX2xp
c3RfbG9jayhzdHJ1Y3QgaWJfdWNvbnRleHRfbG9jayAqbG9jaykNCj4gPj4gK3sNCj4gPj4gKyAg
ICAgbXV0ZXhfaW5pdCgmbG9jay0+bG9jayk7DQo+ID4+ICsgICAgIGtyZWZfaW5pdCgmbG9jay0+
cmVmKTsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIHZvaWQgcmVsZWFzZV91b2JqZWN0
c19saXN0X2xvY2soc3RydWN0IGtyZWYgKnJlZikNCj4gPj4gK3sNCj4gPj4gKyAgICAgc3RydWN0
IGliX3Vjb250ZXh0X2xvY2sgKmxvY2sgPSBjb250YWluZXJfb2YocmVmLA0KPiA+PiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QNCj4gaWJf
dWNvbnRleHRfbG9jaywNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgcmVmKTsNCj4gPj4gKw0KPiA+PiArICAgICBrZnJlZShsb2NrKTsNCj4g
Pj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIHZvaWQgaW5pdF91b2JqKHN0cnVjdCBpYl91b2Jq
ZWN0ICp1b2JqLCB1NjQgdXNlcl9oYW5kbGUsDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgc3Ry
dWN0IGliX3Vjb250ZXh0ICpjb250ZXh0KQ0KPiA+PiArew0KPiA+PiArICAgICBpbml0X3J3c2Vt
KCZ1b2JqLT51c2VjbnQpOw0KPiA+PiArICAgICB1b2JqLT51c2VyX2hhbmRsZSA9IHVzZXJfaGFu
ZGxlOw0KPiA+PiArICAgICB1b2JqLT5jb250ZXh0ICAgICA9IGNvbnRleHQ7DQo+ID4+ICsgICAg
IHVvYmotPmxpdmUgICAgICAgID0gMDsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIGlu
dCBhZGRfdW9iaihzdHJ1Y3QgaWJfdW9iamVjdCAqdW9iaikNCj4gPj4gK3sNCj4gPj4gKyAgICAg
aW50IHJldDsNCj4gPj4gKw0KPiA+PiArICAgICBpZHJfcHJlbG9hZChHRlBfS0VSTkVMKTsNCj4g
Pj4gKyAgICAgc3Bpbl9sb2NrKCZ1b2JqLT5jb250ZXh0LT5kZXZpY2UtPmlkcl9sb2NrKTsNCj4g
Pj4gKw0KPiA+PiArICAgICByZXQgPSBpZHJfYWxsb2MoJnVvYmotPmNvbnRleHQtPmRldmljZS0+
aWRyLCB1b2JqLCAwLCAwLA0KPiA+PiBHRlBfTk9XQUlUKTsNCj4gPj4gKyAgICAgaWYgKHJldCA+
PSAwKQ0KPiA+PiArICAgICAgICAgICAgIHVvYmotPmlkID0gcmV0Ow0KPiA+PiArDQo+ID4+ICsg
ICAgIHNwaW5fdW5sb2NrKCZ1b2JqLT5jb250ZXh0LT5kZXZpY2UtPmlkcl9sb2NrKTsNCj4gPj4g
KyAgICAgaWRyX3ByZWxvYWRfZW5kKCk7DQo+ID4+ICsNCj4gPj4gKyAgICAgcmV0dXJuIHJldCA8
IDAgPyByZXQgOiAwOw0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtzdGF0aWMgdm9pZCByZW1vdmVf
dW9iaihzdHJ1Y3QgaWJfdW9iamVjdCAqdW9iaikNCj4gPj4gK3sNCj4gPj4gKyAgICAgc3Bpbl9s
b2NrKCZ1b2JqLT5jb250ZXh0LT5kZXZpY2UtPmlkcl9sb2NrKTsNCj4gPj4gKyAgICAgaWRyX3Jl
bW92ZSgmdW9iai0+Y29udGV4dC0+ZGV2aWNlLT5pZHIsIHVvYmotPmlkKTsNCj4gPj4gKyAgICAg
c3Bpbl91bmxvY2soJnVvYmotPmNvbnRleHQtPmRldmljZS0+aWRyX2xvY2spOw0KPiA+PiArfQ0K
PiA+PiArDQo+ID4+ICtzdGF0aWMgdm9pZCBwdXRfdW9iaihzdHJ1Y3QgaWJfdW9iamVjdCAqdW9i
aikNCj4gPj4gK3sNCj4gPj4gKyAgICAga2ZyZWVfcmN1KHVvYmosIHJjdSk7DQo+ID4+ICt9DQo+
ID4+ICsNCj4gPj4gK3N0YXRpYyBzdHJ1Y3QgaWJfdW9iamVjdCAqZ2V0X3VvYmplY3RfZnJvbV9j
b250ZXh0KHN0cnVjdA0KPiBpYl91Y29udGV4dA0KPiA+PiAqdWNvbnRleHQsDQo+ID4+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzdHJ1Y3QN
Cj4gPj4gdXZlcmJzX3R5cGVfYWxsb2NfYWN0aW9uICp0eXBlLA0KPiA+PiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdTMyIGlkciwNCj4gPj4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudW0NCj4gdXZlcmJz
X2lkcl9hY2Nlc3MgYWNjZXNzKQ0KPiA+PiArew0KPiA+PiArICAgICBzdHJ1Y3QgaWJfdW9iamVj
dCAqdW9iajsNCj4gPj4gKyAgICAgaW50IHJldDsNCj4gPj4gKw0KPiA+PiArICAgICByY3VfcmVh
ZF9sb2NrKCk7DQo+ID4+ICsgICAgIHVvYmogPSBnZXRfdW9iaihpZHIsIHVjb250ZXh0KTsNCj4g
Pj4gKyAgICAgaWYgKCF1b2JqKQ0KPiA+PiArICAgICAgICAgICAgIGdvdG8gZnJlZTsNCj4gPj4g
Kw0KPiA+PiArICAgICBpZiAodW9iai0+dHlwZSAhPSB0eXBlKSB7DQo+ID4+ICsgICAgICAgICAg
ICAgdW9iaiA9IE5VTEw7DQo+ID4+ICsgICAgICAgICAgICAgZ290byBmcmVlOw0KPiA+PiArICAg
ICB9DQo+ID4+ICsNCj4gPj4gKyAgICAgcmV0ID0gdXZlcmJzX2xvY2tfb2JqZWN0KHVvYmosIGFj
Y2Vzcyk7DQo+ID4+ICsgICAgIGlmIChyZXQpDQo+ID4+ICsgICAgICAgICAgICAgdW9iaiA9IEVS
Ul9QVFIocmV0KTsNCj4gPj4gK2ZyZWU6DQo+ID4+ICsgICAgIHJjdV9yZWFkX3VubG9jaygpOw0K
PiA+PiArICAgICByZXR1cm4gdW9iajsNCj4gPj4gKw0KPiA+PiArICAgICByZXR1cm4gTlVMTDsN
Cj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIGludCBpYl91dmVyYnNfdW9iamVjdF9hZGQo
c3RydWN0IGliX3VvYmplY3QgKnVvYmplY3QsDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBjb25zdCBzdHJ1Y3QgdXZlcmJzX3R5cGVfYWxsb2NfYWN0aW9uDQo+ID4+ICp1b2Jq
ZWN0X3R5cGUpDQo+ID4+ICt7DQo+ID4+ICsgICAgIHVvYmplY3QtPnR5cGUgPSB1b2JqZWN0X3R5
cGU7DQo+ID4+ICsgICAgIHJldHVybiBhZGRfdW9iaih1b2JqZWN0KTsNCj4gPj4gK30NCj4gPj4g
Kw0KPiA+PiArc3RydWN0IGliX3VvYmplY3QgKnV2ZXJic19nZXRfdHlwZV9mcm9tX2lkcihjb25z
dCBzdHJ1Y3QNCj4gPj4gdXZlcmJzX3R5cGVfYWxsb2NfYWN0aW9uICp0eXBlLA0KPiA+PiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgaWJfdWNvbnRleHQN
Cj4gKnVjb250ZXh0LA0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBlbnVtIHV2ZXJic19pZHJfYWNjZXNzDQo+IGFjY2VzcywNCj4gPj4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDMyX3QgaWRyKQ0KPiA+PiArew0KPiA+
PiArICAgICBzdHJ1Y3QgaWJfdW9iamVjdCAqdW9iajsNCj4gPj4gKyAgICAgaW50IHJldDsNCj4g
Pj4gKw0KPiA+PiArICAgICBpZiAoYWNjZXNzID09IFVWRVJCU19JRFJfQUNDRVNTX05FVykgew0K
PiA+PiArICAgICAgICAgICAgIHVvYmogPSBrbWFsbG9jKHR5cGUtPm9ial9zaXplLCBHRlBfS0VS
TkVMKTsNCj4gPj4gKyAgICAgICAgICAgICBpZiAoIXVvYmopDQo+ID4+ICsgICAgICAgICAgICAg
ICAgICAgICByZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsNCj4gPj4gKw0KPiA+PiArICAgICAgICAg
ICAgIGluaXRfdW9iaih1b2JqLCAwLCB1Y29udGV4dCk7DQo+ID4+ICsNCj4gPj4gKyAgICAgICAg
ICAgICAvKiBsb2NrIGlkciAqLw0KPiA+DQo+ID4gQ29tbWFuZCB0byBsb2NrIGlkciwgYnV0IG5v
IGxvY2sgaXMgb2J0YWluZWQuDQo+ID4NCj4gDQo+IGliX3V2ZXJic191b2JqZWN0X2FkZCBjYWxs
cyBhZGRfdW9iaiB3aGljaCBsb2NrcyB0aGUgSURSLg0KPiANCj4gPj4gKyAgICAgICAgICAgICBy
ZXQgPSBpYl91dmVyYnNfdW9iamVjdF9hZGQodW9iaiwgdHlwZSk7DQo+ID4+ICsgICAgICAgICAg
ICAgaWYgKHJldCkgew0KPiA+PiArICAgICAgICAgICAgICAgICAgICAga2ZyZWUodW9iaik7DQo+
ID4+ICsgICAgICAgICAgICAgICAgICAgICByZXR1cm4gRVJSX1BUUihyZXQpOw0KPiA+PiArICAg
ICAgICAgICAgIH0NCj4gPj4gKw0KPiA+PiArICAgICB9IGVsc2Ugew0KPiA+PiArICAgICAgICAg
ICAgIHVvYmogPSBnZXRfdW9iamVjdF9mcm9tX2NvbnRleHQodWNvbnRleHQsIHR5cGUsIGlkciwN
Cj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY2Vz
cyk7DQo+ID4+ICsNCj4gPj4gKyAgICAgICAgICAgICBpZiAoIXVvYmopDQo+ID4+ICsgICAgICAg
ICAgICAgICAgICAgICByZXR1cm4gRVJSX1BUUigtRU5PRU5UKTsNCj4gPj4gKyAgICAgfQ0KPiA+
PiArDQo+ID4+ICsgICAgIHJldHVybiB1b2JqOw0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtzdHJ1
Y3QgaWJfdW9iamVjdCAqdXZlcmJzX2dldF90eXBlX2Zyb21fZmQoY29uc3Qgc3RydWN0DQo+ID4+
IHV2ZXJic190eXBlX2FsbG9jX2FjdGlvbiAqdHlwZSwNCj4gPj4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgaWJfdWNvbnRleHQNCj4gKnVjb250ZXh0LA0K
PiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudW0gdXZlcmJz
X2lkcl9hY2Nlc3MNCj4gYWNjZXNzLA0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIGludCBmZCkNCj4gPj4gK3sNCj4gPj4gKyAgICAgaWYgKGFjY2VzcyA9PSBV
VkVSQlNfSURSX0FDQ0VTU19ORVcpIHsNCj4gPj4gKyAgICAgICAgICAgICBpbnQgX2ZkOw0KPiA+
PiArICAgICAgICAgICAgIHN0cnVjdCBpYl91b2JqZWN0ICp1b2JqID0gTlVMTDsNCj4gPj4gKyAg
ICAgICAgICAgICBzdHJ1Y3QgZmlsZSAqZmlscDsNCj4gPj4gKw0KPiA+PiArICAgICAgICAgICAg
IF9mZCA9IGdldF91bnVzZWRfZmRfZmxhZ3MoT19DTE9FWEVDKTsNCj4gPj4gKyAgICAgICAgICAg
ICBpZiAoX2ZkIDwgMCB8fCBXQVJOX09OKHR5cGUtPm9ial9zaXplIDwgc2l6ZW9mKHN0cnVjdA0K
PiA+PiBpYl91b2JqZWN0KSkpDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICByZXR1cm4gRVJS
X1BUUihfZmQpOw0KPiA+PiArDQo+ID4+ICsgICAgICAgICAgICAgdW9iaiA9IGttYWxsb2ModHlw
ZS0+b2JqX3NpemUsIEdGUF9LRVJORUwpOw0KPiA+PiArICAgICAgICAgICAgIGluaXRfdW9iaih1
b2JqLCAwLCB1Y29udGV4dCk7DQo+ID4+ICsNCj4gPj4gKyAgICAgICAgICAgICBpZiAoIXVvYmop
DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICByZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsNCj4g
Pj4gKw0KPiA+PiArICAgICAgICAgICAgIGZpbHAgPSBhbm9uX2lub2RlX2dldGZpbGUodHlwZS0+
ZmQubmFtZSwgdHlwZS0NCj4gPmZkLmZvcHMsDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICB1b2JqICsgMSwgdHlwZS0+ZmQuZmxhZ3MpOw0KPiA+PiArICAgICAg
ICAgICAgIGlmIChJU19FUlIoZmlscCkpIHsNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgIHB1
dF91bnVzZWRfZmQoX2ZkKTsNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgIGtmcmVlKHVvYmop
Ow0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICh2b2lkICopZmlscDsNCj4gPj4g
KyAgICAgICAgICAgICB9DQo+ID4+ICsNCj4gPj4gKyAgICAgICAgICAgICB1b2JqLT50eXBlID0g
dHlwZTsNCj4gPj4gKyAgICAgICAgICAgICB1b2JqLT5pZCA9IF9mZDsNCj4gPj4gKyAgICAgICAg
ICAgICB1b2JqLT5vYmplY3QgPSBmaWxwOw0KPiA+PiArDQo+ID4+ICsgICAgICAgICAgICAgcmV0
dXJuIHVvYmo7DQo+ID4+ICsgICAgIH0gZWxzZSBpZiAoYWNjZXNzID09IFVWRVJCU19JRFJfQUND
RVNTX1JFQUQpIHsNCj4gPj4gKyAgICAgICAgICAgICBzdHJ1Y3QgZmlsZSAqZiA9IGZnZXQoZmQp
Ow0KPiA+PiArICAgICAgICAgICAgIHN0cnVjdCBpYl91b2JqZWN0ICp1b2JqZWN0Ow0KPiA+PiAr
DQo+ID4+ICsgICAgICAgICAgICAgaWYgKCFmKQ0KPiA+PiArICAgICAgICAgICAgICAgICAgICAg
cmV0dXJuIEVSUl9QVFIoLUVCQURGKTsNCj4gPj4gKw0KPiA+PiArICAgICAgICAgICAgIHVvYmpl
Y3QgPSBmLT5wcml2YXRlX2RhdGEgLSBzaXplb2Yoc3RydWN0IGliX3VvYmplY3QpOw0KPiA+PiAr
ICAgICAgICAgICAgIGlmIChmLT5mX29wICE9IHR5cGUtPmZkLmZvcHMgfHwNCj4gPj4gKyAgICAg
ICAgICAgICAgICAgIXVvYmplY3QtPmxpdmUpIHsNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAg
IGZwdXQoZik7DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICByZXR1cm4gRVJSX1BUUigtRUJB
REYpOw0KPiA+PiArICAgICAgICAgICAgIH0NCj4gPj4gKw0KPiA+PiArICAgICAgICAgICAgIC8q
DQo+ID4+ICsgICAgICAgICAgICAgICogTm8gbmVlZCB0byBwcm90ZWN0IGl0IHdpdGggYSByZWYg
Y291bnQsIGFzIGZnZXQNCj4gPj4gaW5jcmVhc2VzDQo+ID4+ICsgICAgICAgICAgICAgICogZl9j
b3VudC4NCj4gPj4gKyAgICAgICAgICAgICAgKi8NCj4gPj4gKyAgICAgICAgICAgICByZXR1cm4g
dW9iamVjdDsNCj4gPj4gKyAgICAgfSBlbHNlIHsNCj4gPj4gKyAgICAgICAgICAgICByZXR1cm4g
RVJSX1BUUigtRU9QTk9UU1VQUCk7DQo+ID4+ICsgICAgIH0NCj4gPj4gK30NCj4gPj4gKw0KPiA+
PiArc3RhdGljIHZvaWQgaWJfdXZlcmJzX3VvYmplY3RfZW5hYmxlKHN0cnVjdCBpYl91b2JqZWN0
ICp1b2JqZWN0KQ0KPiA+PiArew0KPiA+PiArICAgICBtdXRleF9sb2NrKCZ1b2JqZWN0LT5jb250
ZXh0LT51b2JqZWN0c19sb2NrLT5sb2NrKTsNCj4gPj4gKyAgICAgbGlzdF9hZGQoJnVvYmplY3Qt
Pmxpc3QsICZ1b2JqZWN0LT5jb250ZXh0LT51b2JqZWN0cyk7DQo+ID4+ICsgICAgIG11dGV4X3Vu
bG9jaygmdW9iamVjdC0+Y29udGV4dC0+dW9iamVjdHNfbG9jay0+bG9jayk7DQo+ID4NCj4gPiBX
aHkgbm90IGp1c3QgaW5zZXJ0IHRoZSBvYmplY3QgaW50byB0aGUgbGlzdCBvbiBjcmVhdGlvbj8N
Cj4gPg0KPiA+PiArICAgICB1b2JqZWN0LT5saXZlID0gMTsNCj4gPg0KPiA+IFNlZSBteSBjb21t
ZW50cyBhYm92ZSBvbiByZW1vdmluZyB0aGUgbGl2ZSBmaWVsZC4NCj4gPg0KPiANCj4gU2VlbXMg
dGhhdCB0aGUgbGlzdCBjb3VsZCBzdWZmaWNlLCBidXQgSSdsbCBsb29rIGludG8gdGhhdC4NCj4g
DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gK3N0YXRpYyB2b2lkIGliX3V2ZXJic191b2JqZWN0X3Jl
bW92ZShzdHJ1Y3QgaWJfdW9iamVjdCAqdW9iamVjdCwNCj4gYm9vbA0KPiA+PiBsb2NrKQ0KPiA+
PiArew0KPiA+PiArICAgICAvKg0KPiA+PiArICAgICAgKiBDYWxsaW5nIHJlbW92ZSByZXF1aXJl
cyBleGNsdXNpdmUgYWNjZXNzLCBzbyBpdCdzIG5vdA0KPiBwb3NzaWJsZQ0KPiA+PiArICAgICAg
KiBhbm90aGVyIHRocmVhZCB3aWxsIHVzZSBvdXIgb2JqZWN0Lg0KPiA+PiArICAgICAgKi8NCj4g
Pj4gKyAgICAgdW9iamVjdC0+bGl2ZSA9IDA7DQo+ID4+ICsgICAgIHVvYmplY3QtPnR5cGUtPmZy
ZWVfZm4odW9iamVjdC0+dHlwZSwgdW9iamVjdCk7DQo+ID4+ICsgICAgIGlmIChsb2NrKQ0KPiA+
PiArICAgICAgICAgICAgIG11dGV4X2xvY2soJnVvYmplY3QtPmNvbnRleHQtPnVvYmplY3RzX2xv
Y2stPmxvY2spOw0KPiA+PiArICAgICBsaXN0X2RlbCgmdW9iamVjdC0+bGlzdCk7DQo+ID4+ICsg
ICAgIGlmIChsb2NrKQ0KPiA+PiArICAgICAgICAgICAgIG11dGV4X3VubG9jaygmdW9iamVjdC0+
Y29udGV4dC0+dW9iamVjdHNfbG9jay0+bG9jayk7DQo+ID4+ICsgICAgIHJlbW92ZV91b2JqKHVv
YmplY3QpOw0KPiA+PiArICAgICBwdXRfdW9iaih1b2JqZWN0KTsNCj4gPj4gK30NCj4gPj4gKw0K
PiA+PiArc3RhdGljIHZvaWQgdXZlcmJzX3VubG9ja19pZHIoc3RydWN0IGliX3VvYmplY3QgKnVv
YmosDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnVtIHV2ZXJic19pZHJfYWNj
ZXNzIGFjY2VzcywNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb2wgc3VjY2Vz
cykNCj4gPj4gK3sNCj4gPj4gKyAgICAgc3dpdGNoIChhY2Nlc3MpIHsNCj4gPj4gKyAgICAgY2Fz
ZSBVVkVSQlNfSURSX0FDQ0VTU19SRUFEOg0KPiA+PiArICAgICAgICAgICAgIHVwX3JlYWQoJnVv
YmotPnVzZWNudCk7DQo+ID4+ICsgICAgICAgICAgICAgYnJlYWs7DQo+ID4+ICsgICAgIGNhc2Ug
VVZFUkJTX0lEUl9BQ0NFU1NfTkVXOg0KPiA+PiArICAgICAgICAgICAgIGlmIChzdWNjZXNzKSB7
DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICBpYl91dmVyYnNfdW9iamVjdF9lbmFibGUodW9i
aik7DQo+ID4+ICsgICAgICAgICAgICAgfSBlbHNlIHsNCj4gPj4gKyAgICAgICAgICAgICAgICAg
ICAgIHJlbW92ZV91b2JqKHVvYmopOw0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgcHV0X3Vv
YmoodW9iaik7DQo+ID4+ICsgICAgICAgICAgICAgfQ0KPiA+PiArICAgICAgICAgICAgIGJyZWFr
Ow0KPiA+PiArICAgICBjYXNlIFVWRVJCU19JRFJfQUNDRVNTX1dSSVRFOg0KPiA+PiArICAgICAg
ICAgICAgIHVwX3dyaXRlKCZ1b2JqLT51c2VjbnQpOw0KPiA+PiArICAgICAgICAgICAgIGJyZWFr
Ow0KPiA+PiArICAgICBjYXNlIFVWRVJCU19JRFJfQUNDRVNTX0RFU1RST1k6DQo+ID4+ICsgICAg
ICAgICAgICAgaWYgKHN1Y2Nlc3MpDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICBpYl91dmVy
YnNfdW9iamVjdF9yZW1vdmUodW9iaiwgdHJ1ZSk7DQo+ID4+ICsgICAgICAgICAgICAgZWxzZQ0K
PiA+PiArICAgICAgICAgICAgICAgICAgICAgdXBfd3JpdGUoJnVvYmotPnVzZWNudCk7DQo+ID4+
ICsgICAgICAgICAgICAgYnJlYWs7DQo+ID4+ICsgICAgIH0NCj4gPj4gK30NCj4gPj4gKw0KPiA+
PiArc3RhdGljIHZvaWQgdXZlcmJzX3VubG9ja19mZChzdHJ1Y3QgaWJfdW9iamVjdCAqdW9iaiwN
Cj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgZW51bSB1dmVyYnNfaWRyX2FjY2VzcyBh
Y2Nlc3MsDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb2wgc3VjY2VzcykNCj4g
Pj4gK3sNCj4gPj4gKyAgICAgc3RydWN0IGZpbGUgKmZpbHAgPSB1b2JqLT5vYmplY3Q7DQo+ID4+
ICsNCj4gPj4gKyAgICAgaWYgKGFjY2VzcyA9PSBVVkVSQlNfSURSX0FDQ0VTU19ORVcpIHsNCj4g
Pj4gKyAgICAgICAgICAgICBpZiAoc3VjY2Vzcykgew0KPiA+PiArICAgICAgICAgICAgICAgICAg
ICAga3JlZl9nZXQoJnVvYmotPmNvbnRleHQtPnVmaWxlLT5yZWYpOw0KPiA+PiArICAgICAgICAg
ICAgICAgICAgICAgdW9iai0+dW9iamVjdHNfbG9jayA9IHVvYmotPmNvbnRleHQtDQo+ID51b2Jq
ZWN0c19sb2NrOw0KPiA+PiArICAgICAgICAgICAgICAgICAgICAga3JlZl9nZXQoJnVvYmotPnVv
YmplY3RzX2xvY2stPnJlZik7DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICBpYl91dmVyYnNf
dW9iamVjdF9lbmFibGUodW9iaik7DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICBmZF9pbnN0
YWxsKHVvYmotPmlkLCB1b2JqLT5vYmplY3QpOw0KPiA+DQo+ID4gSSBkb24ndCBnZXQgdGhpcy4g
IFRoZSBmdW5jdGlvbiBpcyB1bmxvY2tpbmcgc29tZXRoaW5nLCBidXQgdGhlcmUgYXJlDQo+IGNh
bGxzIHRvIGdldCBrcmVmcz8NCj4gPg0KPiANCj4gQmVmb3JlIGludm9raW5nIHRoZSB1c2VyJ3Mg
Y2FsbGJhY2ssIHdlJ3JlIGZpcnN0IGxvY2tpbmcgYWxsIG9iamVjdHMNCj4gYW5kIGFmdGVyd2Fy
ZHMgd2UncmUgdW5sb2NraW5nIHRoZW0uIFdoZW4gd2UgbmVlZCB0byBjcmVhdGUgYSBuZXcNCj4g
b2JqZWN0LCB0aGUgbG9jayBiZWNvbWVzIG9iamVjdCBjcmVhdGlvbiBhbmQgdGhlIHVubG9jayBj
b3VsZCBiZWNvbWUNCj4gKGFzc3VtaW5nIHRoZSB1c2VyJ3MgY2FsbGJhY2sgc3VjY2VlZGVkKSBl
bmFibGluZyB0aGlzIG5ldyBvYmplY3QuDQo+IFdoZW4geW91IGFkZCBhIG5ldyBvYmplY3QgKG9y
IGZkIGluIHRoaXMgY2FzZSksIHdlIHRha2UgYSByZWZlcmVuY2UNCj4gY291bnQgdG8gYm90aCB0
aGUgdXZlcmJzX2ZpbGUgYW5kIHRoZSBsb2NraW5nIGNvbnRleHQuDQo+IA0KPiA+PiArICAgICAg
ICAgICAgIH0gZWxzZSB7DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICBmcHV0KHVvYmotPm9i
amVjdCk7DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICBwdXRfdW51c2VkX2ZkKHVvYmotPmlk
KTsNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgIGtmcmVlKHVvYmopOw0KPiA+PiArICAgICAg
ICAgICAgIH0NCj4gPj4gKyAgICAgfSBlbHNlIHsNCj4gPj4gKyAgICAgICAgICAgICBmcHV0KGZp
bHApOw0KPiA+PiArICAgICB9DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gK3ZvaWQgdXZlcmJzX3Vu
bG9ja19vYmplY3Qoc3RydWN0IGliX3VvYmplY3QgKnVvYmosDQo+ID4+ICsgICAgICAgICAgICAg
ICAgICAgICAgIGVudW0gdXZlcmJzX2lkcl9hY2Nlc3MgYWNjZXNzLA0KPiA+PiArICAgICAgICAg
ICAgICAgICAgICAgICBib29sIHN1Y2Nlc3MpDQo+ID4+ICt7DQo+ID4+ICsgICAgIGlmICh1b2Jq
LT50eXBlLT50eXBlID09IFVWRVJCU19BVFRSX1RZUEVfSURSKQ0KPiA+PiArICAgICAgICAgICAg
IHV2ZXJic191bmxvY2tfaWRyKHVvYmosIGFjY2Vzcywgc3VjY2Vzcyk7DQo+ID4+ICsgICAgIGVs
c2UgaWYgKHVvYmotPnR5cGUtPnR5cGUgPT0gVVZFUkJTX0FUVFJfVFlQRV9GRCkNCj4gPj4gKyAg
ICAgICAgICAgICB1dmVyYnNfdW5sb2NrX2ZkKHVvYmosIGFjY2Vzcywgc3VjY2Vzcyk7DQo+ID4+
ICsgICAgIGVsc2UNCj4gPj4gKyAgICAgICAgICAgICBXQVJOX09OKHRydWUpOw0KPiA+PiArfQ0K
PiA+PiArDQo+ID4+ICtzdGF0aWMgdm9pZCBpYl91dmVyYnNfcmVtb3ZlX2ZkKHN0cnVjdCBpYl91
b2JqZWN0ICp1b2JqZWN0KQ0KPiA+PiArew0KPiA+PiArICAgICAvKg0KPiA+PiArICAgICAgKiB1
c2VyIHNob3VsZCByZWxlYXNlIHRoZSB1b2JqZWN0IGluIHRoZSByZWxlYXNlDQo+ID4+ICsgICAg
ICAqIGNhbGxiYWNrLg0KPiA+PiArICAgICAgKi8NCj4gPj4gKyAgICAgaWYgKHVvYmplY3QtPmxp
dmUpIHsNCj4gPj4gKyAgICAgICAgICAgICB1b2JqZWN0LT5saXZlID0gMDsNCj4gPj4gKyAgICAg
ICAgICAgICBsaXN0X2RlbCgmdW9iamVjdC0+bGlzdCk7DQo+ID4+ICsgICAgICAgICAgICAgdW9i
amVjdC0+dHlwZS0+ZnJlZV9mbih1b2JqZWN0LT50eXBlLCB1b2JqZWN0KTsNCj4gPj4gKyAgICAg
ICAgICAgICBrcmVmX3B1dCgmdW9iamVjdC0+Y29udGV4dC0+dWZpbGUtPnJlZiwNCj4gPj4gaWJf
dXZlcmJzX3JlbGVhc2VfZmlsZSk7DQo+ID4+ICsgICAgICAgICAgICAgdW9iamVjdC0+Y29udGV4
dCA9IE5VTEw7DQo+ID4+ICsgICAgIH0NCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArdm9pZCBpYl91
dmVyYnNfY2xvc2VfZmQoc3RydWN0IGZpbGUgKmYpDQo+ID4+ICt7DQo+ID4+ICsgICAgIHN0cnVj
dCBpYl91b2JqZWN0ICp1b2JqZWN0ID0gZi0+cHJpdmF0ZV9kYXRhIC0gc2l6ZW9mKHN0cnVjdA0K
PiA+PiBpYl91b2JqZWN0KTsNCj4gPj4gKw0KPiA+PiArICAgICBtdXRleF9sb2NrKCZ1b2JqZWN0
LT51b2JqZWN0c19sb2NrLT5sb2NrKTsNCj4gPj4gKyAgICAgaWYgKHVvYmplY3QtPmxpdmUpIHsN
Cj4gPj4gKyAgICAgICAgICAgICB1b2JqZWN0LT5saXZlID0gMDsNCj4gPj4gKyAgICAgICAgICAg
ICBsaXN0X2RlbCgmdW9iamVjdC0+bGlzdCk7DQo+ID4+ICsgICAgICAgICAgICAga3JlZl9wdXQo
JnVvYmplY3QtPmNvbnRleHQtPnVmaWxlLT5yZWYsDQo+ID4+IGliX3V2ZXJic19yZWxlYXNlX2Zp
bGUpOw0KPiA+PiArICAgICAgICAgICAgIHVvYmplY3QtPmNvbnRleHQgPSBOVUxMOw0KPiA+PiAr
ICAgICB9DQo+ID4+ICsgICAgIG11dGV4X3VubG9jaygmdW9iamVjdC0+dW9iamVjdHNfbG9jay0+
bG9jayk7DQo+ID4+ICsgICAgIGtyZWZfcHV0KCZ1b2JqZWN0LT51b2JqZWN0c19sb2NrLT5yZWYs
DQo+ID4+IHJlbGVhc2VfdW9iamVjdHNfbGlzdF9sb2NrKTsNCj4gPj4gK30NCj4gPj4gKw0KPiA+
PiArdm9pZCBpYl91dmVyYnNfY2xlYW51cF9mZCh2b2lkICpwcml2YXRlX2RhdGEpDQo+ID4+ICt7
DQo+ID4+ICsgICAgIHN0cnVjdCBpYl91Ym9qZWN0ICp1b2JqZWN0ID0gcHJpdmF0ZV9kYXRhIC0g
c2l6ZW9mKHN0cnVjdA0KPiA+PiBpYl91b2JqZWN0KTsNCj4gPj4gKw0KPiA+PiArICAgICBrZnJl
ZSh1b2JqZWN0KTsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArdm9pZCB1dmVyYnNfdW5sb2NrX29i
amVjdHMoc3RydWN0IHV2ZXJic19hdHRyX2FycmF5ICphdHRyX2FycmF5LA0KPiA+PiArICAgICAg
ICAgICAgICAgICAgICAgICAgc2l6ZV90IG51bSwNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAg
ICAgIGNvbnN0IHN0cnVjdCB1dmVyYnNfYWN0aW9uX3NwZWMgKnNwZWMsDQo+ID4+ICsgICAgICAg
ICAgICAgICAgICAgICAgICBib29sIHN1Y2Nlc3MpDQo+ID4+ICt7DQo+ID4+ICsgICAgIHVuc2ln
bmVkIGludCBpOw0KPiA+PiArDQo+ID4+ICsgICAgIGZvciAoaSA9IDA7IGkgPCBudW07IGkrKykg
ew0KPiA+PiArICAgICAgICAgICAgIHN0cnVjdCB1dmVyYnNfYXR0cl9hcnJheSAqYXR0cl9zcGVj
X2FycmF5ID0NCj4gJmF0dHJfYXJyYXlbaV07DQo+ID4+ICsgICAgICAgICAgICAgY29uc3Qgc3Ry
dWN0IHV2ZXJic19hdHRyX2dyb3VwX3NwZWMgKmdyb3VwX3NwZWMgPQ0KPiA+PiArICAgICAgICAg
ICAgICAgICAgICAgc3BlYy0+YXR0cl9ncm91cHNbaV07DQo+ID4+ICsgICAgICAgICAgICAgdW5z
aWduZWQgaW50IGo7DQo+ID4+ICsNCj4gPj4gKyAgICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwg
YXR0cl9zcGVjX2FycmF5LT5udW1fYXR0cnM7IGorKykgew0KPiA+PiArICAgICAgICAgICAgICAg
ICAgICAgc3RydWN0IHV2ZXJic19hdHRyICphdHRyID0gJmF0dHJfc3BlY19hcnJheS0NCj4gPj4g
PmF0dHJzW2pdOw0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgc3RydWN0IHV2ZXJic19hdHRy
X3NwZWMgKnNwZWMgPSAmZ3JvdXBfc3BlYy0NCj4gPj4gPmF0dHJzW2pdOw0KPiA+PiArDQo+ID4+
ICsgICAgICAgICAgICAgICAgICAgICBpZiAoIWF0dHItPnZhbGlkKQ0KPiA+PiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsNCj4gPj4gKw0KPiA+PiArICAgICAgICAgICAg
ICAgICAgICAgaWYgKHNwZWMtPnR5cGUgPT0gVVZFUkJTX0FUVFJfVFlQRV9JRFIgfHwNCj4gPj4g
KyAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjLT50eXBlID09IFVWRVJCU19BVFRSX1RZUEVf
RkQpDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qDQo+ID4+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAqIHJlZmNvdW50cyBzaG91bGQgYmUgaGFuZGxlZCBhdCB0
aGUNCj4gb2JqZWN0DQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqIGxldmVs
IGFuZCBub3QgYXQgdGhlIHVvYmplY3QgbGV2ZWwuDQo+ID4+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAqLw0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1dmVyYnNf
dW5sb2NrX29iamVjdChhdHRyLQ0KPiA+b2JqX2F0dHIudW9iamVjdCwNCj4gPj4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlYy0+b2JqLmFjY2Vz
cywNCj4gc3VjY2Vzcyk7DQo+ID4+ICsgICAgICAgICAgICAgfQ0KPiA+PiArICAgICB9DQo+ID4+
ICt9DQo+ID4+ICsNCj4gPj4gK3N0YXRpYyB1bnNpZ25lZCBpbnQgZ2V0X3R5cGVfb3JkZXJzKGNv
bnN0IHN0cnVjdCB1dmVyYnNfdHlwZXNfZ3JvdXANCj4gPj4gKnR5cGVzX2dyb3VwKQ0KPiA+PiAr
ew0KPiA+PiArICAgICB1bnNpZ25lZCBpbnQgaTsNCj4gPj4gKyAgICAgdW5zaWduZWQgaW50IG1h
eCA9IDA7DQo+ID4+ICsNCj4gPj4gKyAgICAgZm9yIChpID0gMDsgaSA8IHR5cGVzX2dyb3VwLT5u
dW1fZ3JvdXBzOyBpKyspIHsNCj4gPj4gKyAgICAgICAgICAgICB1bnNpZ25lZCBpbnQgajsNCj4g
Pj4gKyAgICAgICAgICAgICBjb25zdCBzdHJ1Y3QgdXZlcmJzX3R5cGVzICp0eXBlcyA9IHR5cGVz
X2dyb3VwLQ0KPiA+PiA+dHlwZV9ncm91cHNbaV07DQo+ID4+ICsNCj4gPj4gKyAgICAgICAgICAg
ICBmb3IgKGogPSAwOyBqIDwgdHlwZXMtPm51bV90eXBlczsgaisrKSB7DQo+ID4+ICsgICAgICAg
ICAgICAgICAgICAgICBpZiAoIXR5cGVzLT50eXBlc1tqXSB8fCAhdHlwZXMtPnR5cGVzW2pdLQ0K
PiA+YWxsb2MpDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOw0K
PiA+PiArICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVzLT50eXBlc1tqXS0+YWxsb2MtPm9y
ZGVyID4gbWF4KQ0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXggPSB0eXBl
cy0+dHlwZXNbal0tPmFsbG9jLT5vcmRlcjsNCj4gPj4gKyAgICAgICAgICAgICB9DQo+ID4+ICsg
ICAgIH0NCj4gPj4gKw0KPiA+PiArICAgICByZXR1cm4gbWF4Ow0KPiA+PiArfQ0KPiA+PiArDQo+
ID4+ICt2b2lkIGliX3V2ZXJic191b2JqZWN0X3R5cGVfY2xlYW51cF91Y29udGV4dChzdHJ1Y3Qg
aWJfdWNvbnRleHQNCj4gPj4gKnVjb250ZXh0LA0KPiA+PiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3RydWN0DQo+IHV2ZXJic190eXBlc19ncm91cA0K
PiA+PiAqdHlwZXNfZ3JvdXApDQo+ID4+ICt7DQo+ID4+ICsgICAgIHVuc2lnbmVkIGludCBudW1f
b3JkZXJzID0gZ2V0X3R5cGVfb3JkZXJzKHR5cGVzX2dyb3VwKTsNCj4gPj4gKyAgICAgdW5zaWdu
ZWQgaW50IGk7DQo+ID4+ICsNCj4gPj4gKyAgICAgZm9yIChpID0gMDsgaSA8PSBudW1fb3JkZXJz
OyBpKyspIHsNCj4gPj4gKyAgICAgICAgICAgICBzdHJ1Y3QgaWJfdW9iamVjdCAqb2JqLCAqbmV4
dF9vYmo7DQo+ID4+ICsNCj4gPj4gKyAgICAgICAgICAgICAvKg0KPiA+PiArICAgICAgICAgICAg
ICAqIE5vIG5lZWQgdG8gdGFrZSBsb2NrIGhlcmUsIGFzIGNsZWFudXAgc2hvdWxkIGJlDQo+IGNh
bGxlZA0KPiA+PiArICAgICAgICAgICAgICAqIGFmdGVyIGFsbCBjb21tYW5kcyBmaW5pc2hlZCBl
eGVjdXRpbmcuIE5ld2x5DQo+IGV4ZWN1dGVkDQo+ID4+ICsgICAgICAgICAgICAgICogY29tbWFu
ZHMgc2hvdWxkIGZhaWwuDQo+ID4+ICsgICAgICAgICAgICAgICovDQo+ID4+ICsgICAgICAgICAg
ICAgbXV0ZXhfbG9jaygmdWNvbnRleHQtPnVvYmplY3RzX2xvY2stPmxvY2spOw0KPiA+DQo+ID4g
SXQncyByZWFsbHkgY29uZnVzaW5nIHRvIHNlZSBhIGNvbW1lbnQgYWJvdXQgJ25vIG5lZWQgdG8g
dGFrZSBsb2NrJw0KPiBpbW1lZGlhdGVseSBmb2xsb3dlZCBieSBhIGNhbGwgdG8gbG9jay4NCj4g
Pg0KPiANCj4gWWVhaCA6KSBUaGF0IHdhcyBiZWZvcmUgYWRkaW5nIHRoZSBmZC4gSSdsbCBkZWxl
dGUgdGhlIGNvbW1lbnQuDQo+IA0KPiA+PiArICAgICAgICAgICAgIGxpc3RfZm9yX2VhY2hfZW50
cnlfc2FmZShvYmosIG5leHRfb2JqLCAmdWNvbnRleHQtDQo+ID4+ID51b2JqZWN0cywNCj4gPj4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCkNCj4gPj4gKyAgICAg
ICAgICAgICAgICAgICAgIGlmIChvYmotPnR5cGUtPm9yZGVyID09IGkpIHsNCj4gPj4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG9iai0+dHlwZS0+dHlwZSA9PQ0KPiBVVkVSQlNf
QVRUUl9UWVBFX0lEUikNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBpYl91dmVyYnNfdW9iamVjdF9yZW1vdmUob2JqLA0KPiBmYWxzZSk7DQo+ID4+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIGVsc2UNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBpYl91dmVyYnNfcmVtb3ZlX2ZkKG9iaik7DQo+ID4+ICsgICAgICAgICAg
ICAgICAgICAgICB9DQo+ID4+ICsgICAgICAgICAgICAgbXV0ZXhfdW5sb2NrKCZ1Y29udGV4dC0+
dW9iamVjdHNfbG9jay0+bG9jayk7DQo+ID4+ICsgICAgIH0NCj4gPj4gKyAgICAga3JlZl9wdXQo
JnVjb250ZXh0LT51b2JqZWN0c19sb2NrLT5yZWYsDQo+ID4+IHJlbGVhc2VfdW9iamVjdHNfbGlz
dF9sb2NrKTsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiAraW50IGliX3V2ZXJic191b2JqZWN0X3R5
cGVfaW5pdGlhbGl6ZV91Y29udGV4dChzdHJ1Y3QgaWJfdWNvbnRleHQNCj4gPj4gKnVjb250ZXh0
KQ0KPiA+DQo+ID4gUGxlYXNlIHdvcmsgb24gdGhlIGZ1bmN0aW9uIG5hbWVzLiAgVGhpcyBpcyBo
b3JyZW5kb3VzbHkgbG9uZyBhbmQNCj4gc3RpbGwgZG9lc24ndCBoZWxwIGRlc2NyaWJlIHdoYXQg
aXQgZG9lcy4NCj4gPg0KPiANCj4gVGhpcyBqdXN0IGluaXRpYWxpemVkIHRoZSB0eXBlcyBwYXJ0
IG9mIHRoZSB1Y29udGV4dC4gQW55IHN1Z2dlc3Rpb25zPw0KPiANCj4gPj4gK3sNCj4gPj4gKyAg
ICAgdWNvbnRleHQtPnVvYmplY3RzX2xvY2sgPSBrbWFsbG9jKHNpemVvZigqdWNvbnRleHQtDQo+
ID4+ID51b2JqZWN0c19sb2NrKSwNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIEdGUF9LRVJORUwpOw0KPiA+PiArICAgICBpZiAoIXVjb250ZXh0LT51b2JqZWN0
c19sb2NrKQ0KPiA+PiArICAgICAgICAgICAgIHJldHVybiAtRU5PTUVNOw0KPiA+PiArDQo+ID4+
ICsgICAgIGluaXRfdW9iamVjdHNfbGlzdF9sb2NrKHVjb250ZXh0LT51b2JqZWN0c19sb2NrKTsN
Cj4gPj4gKyAgICAgSU5JVF9MSVNUX0hFQUQoJnVjb250ZXh0LT51b2JqZWN0cyk7DQo+ID4+ICsN
Cj4gPj4gKyAgICAgcmV0dXJuIDA7DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gK3ZvaWQgaWJfdXZl
cmJzX3VvYmplY3RfdHlwZV9yZWxlYXNlX3Vjb250ZXh0KHN0cnVjdCBpYl91Y29udGV4dA0KPiA+
PiAqdWNvbnRleHQpDQo+ID4+ICt7DQo+ID4+ICsgICAgIGtmcmVlKHVjb250ZXh0LT51b2JqZWN0
c19sb2NrKTsNCj4gPj4gK30NCj4gPg0KPiA+IE5vIG5lZWQgdG8gd3JhcCBhIGNhbGwgdG8gJ2Zy
ZWUnLg0KPiA+DQo+IA0KPiBJbiBvcmRlciB0byBhYnN0cmFjdCBhd2F5IHRoZSB1Y29udGV4dCB0
eXBlIGRhdGEgc3RydWN0dXJlLg0KPiANCj4gPj4gKw0KPiA+PiBkaWZmIC0tZ2l0IGEvZHJpdmVy
cy9pbmZpbmliYW5kL2NvcmUvcmRtYV9jb3JlLmgNCj4gPj4gYi9kcml2ZXJzL2luZmluaWJhbmQv
Y29yZS9yZG1hX2NvcmUuaA0KPiA+PiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+PiBpbmRleCAw
MDAwMDAwLi44OTkwMTE1DQo+ID4+IC0tLSAvZGV2L251bGwNCj4gPj4gKysrIGIvZHJpdmVycy9p
bmZpbmliYW5kL2NvcmUvcmRtYV9jb3JlLmgNCj4gPj4gQEAgLTAsMCArMSw3NSBAQA0KPiA+PiAr
LyoNCj4gPj4gKyAqIENvcHlyaWdodCAoYykgMjAwNSBUb3BzcGluIENvbW11bmljYXRpb25zLiAg
QWxsIHJpZ2h0cyByZXNlcnZlZC4NCj4gPj4gKyAqIENvcHlyaWdodCAoYykgMjAwNSwgMjAwNiBD
aXNjbyBTeXN0ZW1zLiAgQWxsIHJpZ2h0cyByZXNlcnZlZC4NCj4gPj4gKyAqIENvcHlyaWdodCAo
YykgMjAwNS0yMDE2IE1lbGxhbm94IFRlY2hub2xvZ2llcy4gQWxsIHJpZ2h0cw0KPiByZXNlcnZl
ZC4NCj4gPj4gKyAqIENvcHlyaWdodCAoYykgMjAwNSBWb2x0YWlyZSwgSW5jLiBBbGwgcmlnaHRz
IHJlc2VydmVkLg0KPiA+PiArICogQ29weXJpZ2h0IChjKSAyMDA1IFBhdGhTY2FsZSwgSW5jLiBB
bGwgcmlnaHRzIHJlc2VydmVkLg0KPiA+PiArICoNCj4gPj4gKyAqIFRoaXMgc29mdHdhcmUgaXMg
YXZhaWxhYmxlIHRvIHlvdSB1bmRlciBhIGNob2ljZSBvZiBvbmUgb2YgdHdvDQo+ID4+ICsgKiBs
aWNlbnNlcy4gIFlvdSBtYXkgY2hvb3NlIHRvIGJlIGxpY2Vuc2VkIHVuZGVyIHRoZSB0ZXJtcyBv
ZiB0aGUNCj4gR05VDQo+ID4+ICsgKiBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIChHUEwpIFZlcnNp
b24gMiwgYXZhaWxhYmxlIGZyb20gdGhlIGZpbGUNCj4gPj4gKyAqIENPUFlJTkcgaW4gdGhlIG1h
aW4gZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUsIG9yIHRoZQ0KPiA+PiArICogT3BlbklC
Lm9yZyBCU0QgbGljZW5zZSBiZWxvdzoNCj4gPj4gKyAqDQo+ID4+ICsgKiAgICAgUmVkaXN0cmli
dXRpb24gYW5kIHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBmb3Jtcywgd2l0aCBvcg0KPiA+PiAr
ICogICAgIHdpdGhvdXQgbW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQg
dGhlDQo+IGZvbGxvd2luZw0KPiA+PiArICogICAgIGNvbmRpdGlvbnMgYXJlIG1ldDoNCj4gPj4g
KyAqDQo+ID4+ICsgKiAgICAgIC0gUmVkaXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3Qg
cmV0YWluIHRoZSBhYm92ZQ0KPiA+PiArICogICAgICAgIGNvcHlyaWdodCBub3RpY2UsIHRoaXMg
bGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUNCj4gZm9sbG93aW5nDQo+ID4+ICsgKiAgICAgICAg
ZGlzY2xhaW1lci4NCj4gPj4gKyAqDQo+ID4+ICsgKiAgICAgIC0gUmVkaXN0cmlidXRpb25zIGlu
IGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZQ0KPiA+PiArICogICAgICAgIGNv
cHlyaWdodCBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUNCj4gZm9sbG93
aW5nDQo+ID4+ICsgKiAgICAgICAgZGlzY2xhaW1lciBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQv
b3Igb3RoZXIgbWF0ZXJpYWxzDQo+ID4+ICsgKiAgICAgICAgcHJvdmlkZWQgd2l0aCB0aGUgZGlz
dHJpYnV0aW9uLg0KPiA+PiArICoNCj4gPj4gKyAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAi
QVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELA0KPiA+PiArICogRVhQUkVTUyBP
UiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTDQo+
IE9GDQo+ID4+ICsgKiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQ
VVJQT1NFIEFORA0KPiA+PiArICogTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBU
SEUgQVVUSE9SUyBPUiBDT1BZUklHSFQNCj4gSE9MREVSUw0KPiA+PiArICogQkUgTElBQkxFIEZP
UiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElODQo+IEFO
DQo+ID4+ICsgKiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5H
IEZST00sIE9VVCBPRiBPUg0KPiBJTg0KPiA+PiArICogQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZU
V0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRQ0KPiA+PiArICogU09GVFdB
UkUuDQo+ID4+ICsgKi8NCj4gPj4gKw0KPiA+PiArI2lmbmRlZiBVT0JKRUNUX0gNCj4gPj4gKyNk
ZWZpbmUgVU9CSkVDVF9IDQo+ID4+ICsNCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9pZHIuaD4NCj4g
Pj4gKyNpbmNsdWRlIDxyZG1hL3V2ZXJic19pb2N0bC5oPg0KPiA+PiArI2luY2x1ZGUgPHJkbWEv
aWJfdmVyYnMuaD4NCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9tdXRleC5oPg0KPiA+PiArDQo+ID4+
ICtjb25zdCBzdHJ1Y3QgdXZlcmJzX3R5cGUgKnV2ZXJic19nZXRfdHlwZShjb25zdCBzdHJ1Y3Qg
aWJfZGV2aWNlDQo+ID4+ICppYmRldiwNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIHVpbnQxNl90IHR5cGUpOw0KPiA+PiArc3RydWN0IGliX3VvYmplY3QgKnV2
ZXJic19nZXRfdHlwZV9mcm9tX2lkcihjb25zdCBzdHJ1Y3QNCj4gPj4gdXZlcmJzX3R5cGVfYWxs
b2NfYWN0aW9uICp0eXBlLA0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBzdHJ1Y3QgaWJfdWNvbnRleHQNCj4gKnVjb250ZXh0LA0KPiA+PiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnVtIHV2ZXJic19pZHJfYWNjZXNzDQo+
IGFjY2VzcywNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
dWludDMyX3QgaWRyKTsNCj4gPj4gK3N0cnVjdCBpYl91b2JqZWN0ICp1dmVyYnNfZ2V0X3R5cGVf
ZnJvbV9mZChjb25zdCBzdHJ1Y3QNCj4gPj4gdXZlcmJzX3R5cGVfYWxsb2NfYWN0aW9uICp0eXBl
LA0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cnVjdCBp
Yl91Y29udGV4dA0KPiAqdWNvbnRleHQsDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgZW51bSB1dmVyYnNfaWRyX2FjY2Vzcw0KPiBhY2Nlc3MsDQo+ID4+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50IGZkKTsNCj4gPj4gK3Zv
aWQgdXZlcmJzX3VubG9ja19vYmplY3Qoc3RydWN0IGliX3VvYmplY3QgKnVvYmosDQo+ID4+ICsg
ICAgICAgICAgICAgICAgICAgICAgIGVudW0gdXZlcmJzX2lkcl9hY2Nlc3MgYWNjZXNzLA0KPiA+
PiArICAgICAgICAgICAgICAgICAgICAgICBib29sIHN1Y2Nlc3MpOw0KPiA+PiArdm9pZCB1dmVy
YnNfdW5sb2NrX29iamVjdHMoc3RydWN0IHV2ZXJic19hdHRyX2FycmF5ICphdHRyX2FycmF5LA0K
PiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZV90IG51bSwNCj4gPj4gKyAgICAgICAg
ICAgICAgICAgICAgICAgIGNvbnN0IHN0cnVjdCB1dmVyYnNfYWN0aW9uX3NwZWMgKnNwZWMsDQo+
ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICBib29sIHN1Y2Nlc3MpOw0KPiA+PiArDQo+ID4+
ICt2b2lkIGliX3V2ZXJic191b2JqZWN0X3R5cGVfY2xlYW51cF91Y29udGV4dChzdHJ1Y3QgaWJf
dWNvbnRleHQNCj4gPj4gKnVjb250ZXh0LA0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgY29uc3Qgc3RydWN0DQo+IHV2ZXJic190eXBlc19ncm91cA0KPiA+
PiAqdHlwZXNfZ3JvdXApOw0KPiA+PiAraW50IGliX3V2ZXJic191b2JqZWN0X3R5cGVfaW5pdGlh
bGl6ZV91Y29udGV4dChzdHJ1Y3QgaWJfdWNvbnRleHQNCj4gPj4gKnVjb250ZXh0KTsNCj4gPj4g
K3ZvaWQgaWJfdXZlcmJzX3VvYmplY3RfdHlwZV9yZWxlYXNlX3Vjb250ZXh0KHN0cnVjdCBpYl91
Y29udGV4dA0KPiA+PiAqdWNvbnRleHQpOw0KPiA+PiArdm9pZCBpYl91dmVyYnNfY2xvc2VfZmQo
c3RydWN0IGZpbGUgKmYpOw0KPiA+PiArdm9pZCBpYl91dmVyYnNfY2xlYW51cF9mZCh2b2lkICpw
cml2YXRlX2RhdGEpOw0KPiA+PiArDQo+ID4+ICtzdGF0aWMgaW5saW5lIHZvaWQgKnV2ZXJic19m
ZF90b19wcml2KHN0cnVjdCBpYl91b2JqZWN0ICp1b2JqKQ0KPiA+PiArew0KPiA+PiArICAgICBy
ZXR1cm4gdW9iaiArIDE7DQo+ID4+ICt9DQo+ID4NCj4gPiBUaGlzIHNlZW1zIGxpa2UgYSByYXRo
ZXIgdXNlbGVzcyBmdW5jdGlvbi4NCj4gPg0KPiANCj4gV2h5PyBUaGUgdXNlciBzaG9sZG4ndCBr
bm93IG9yIGNhcmUgaG93IHdlIHB1dCBvdXIgc3RydWN0cyB0b2dldGhlci4NCj4gDQo+ID4+ICsN
Cj4gPj4gKyNlbmRpZiAvKiBVSURSX0ggKi8NCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvaW5m
aW5pYmFuZC9jb3JlL3V2ZXJicy5oDQo+ID4+IGIvZHJpdmVycy9pbmZpbmliYW5kL2NvcmUvdXZl
cmJzLmgNCj4gPj4gaW5kZXggODA3NDcwNS4uYWU3ZDRiOCAxMDA2NDQNCj4gPj4gLS0tIGEvZHJp
dmVycy9pbmZpbmliYW5kL2NvcmUvdXZlcmJzLmgNCj4gPj4gKysrIGIvZHJpdmVycy9pbmZpbmli
YW5kL2NvcmUvdXZlcmJzLmgNCj4gPj4gQEAgLTE4MCw2ICsxODAsNyBAQCB2b2lkIGlkcl9yZW1v
dmVfdW9iaihzdHJ1Y3QgaWJfdW9iamVjdCAqdW9iaik7DQo+ID4+ICBzdHJ1Y3QgZmlsZSAqaWJf
dXZlcmJzX2FsbG9jX2V2ZW50X2ZpbGUoc3RydWN0IGliX3V2ZXJic19maWxlDQo+ID4+ICp1dmVy
YnNfZmlsZSwNCj4gPj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1
Y3QgaWJfZGV2aWNlICppYl9kZXYsDQo+ID4+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgaW50IGlzX2FzeW5jKTsNCj4gPj4gK3ZvaWQgaWJfdXZlcmJzX3JlbGVhc2VfZmls
ZShzdHJ1Y3Qga3JlZiAqcmVmKTsNCj4gPj4gIHZvaWQgaWJfdXZlcmJzX2ZyZWVfYXN5bmNfZXZl
bnRfZmlsZShzdHJ1Y3QgaWJfdXZlcmJzX2ZpbGUNCj4gPj4gKnV2ZXJic19maWxlKTsNCj4gPj4g
IHN0cnVjdCBpYl91dmVyYnNfZXZlbnRfZmlsZSAqaWJfdXZlcmJzX2xvb2t1cF9jb21wX2ZpbGUo
aW50IGZkKTsNCj4gPj4NCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvaW5maW5pYmFuZC9jb3Jl
L3V2ZXJic19tYWluLmMNCj4gPj4gYi9kcml2ZXJzL2luZmluaWJhbmQvY29yZS91dmVyYnNfbWFp
bi5jDQo+ID4+IGluZGV4IGY3ODM3MjMuLmU2MzM1N2EgMTAwNjQ0DQo+ID4+IC0tLSBhL2RyaXZl
cnMvaW5maW5pYmFuZC9jb3JlL3V2ZXJic19tYWluLmMNCj4gPj4gKysrIGIvZHJpdmVycy9pbmZp
bmliYW5kL2NvcmUvdXZlcmJzX21haW4uYw0KPiA+PiBAQCAtMzQxLDcgKzM0MSw3IEBAIHN0YXRp
YyB2b2lkIGliX3V2ZXJic19jb21wX2RldihzdHJ1Y3QNCj4gPj4gaWJfdXZlcmJzX2RldmljZSAq
ZGV2KQ0KPiA+PiAgICAgICBjb21wbGV0ZSgmZGV2LT5jb21wKTsNCj4gPj4gIH0NCj4gPj4NCj4g
Pj4gLXN0YXRpYyB2b2lkIGliX3V2ZXJic19yZWxlYXNlX2ZpbGUoc3RydWN0IGtyZWYgKnJlZikN
Cj4gPj4gK3ZvaWQgaWJfdXZlcmJzX3JlbGVhc2VfZmlsZShzdHJ1Y3Qga3JlZiAqcmVmKQ0KPiA+
PiAgew0KPiA+PiAgICAgICBzdHJ1Y3QgaWJfdXZlcmJzX2ZpbGUgKmZpbGUgPQ0KPiA+PiAgICAg
ICAgICAgICAgIGNvbnRhaW5lcl9vZihyZWYsIHN0cnVjdCBpYl91dmVyYnNfZmlsZSwgcmVmKTsN
Cj4gPj4gZGlmZiAtLWdpdCBhL2luY2x1ZGUvcmRtYS9pYl92ZXJicy5oIGIvaW5jbHVkZS9yZG1h
L2liX3ZlcmJzLmgNCj4gPj4gaW5kZXggYjVkMjA3NS4uNzI0MDYxNSAxMDA2NDQNCj4gPj4gLS0t
IGEvaW5jbHVkZS9yZG1hL2liX3ZlcmJzLmgNCj4gPj4gKysrIGIvaW5jbHVkZS9yZG1hL2liX3Zl
cmJzLmgNCj4gPj4gQEAgLTEzMjksOCArMTMyOSwxMSBAQCBzdHJ1Y3QgaWJfZm1yX2F0dHIgew0K
PiA+Pg0KPiA+PiAgc3RydWN0IGliX3VtZW07DQo+ID4+DQo+ID4+ICtzdHJ1Y3QgaWJfdWNvbnRl
eHRfbG9jazsNCj4gPj4gKw0KPiA+PiAgc3RydWN0IGliX3Vjb250ZXh0IHsNCj4gPj4gICAgICAg
c3RydWN0IGliX2RldmljZSAgICAgICAqZGV2aWNlOw0KPiA+PiArICAgICBzdHJ1Y3QgaWJfdXZl
cmJzX2ZpbGUgICp1ZmlsZTsNCj4gPj4gICAgICAgc3RydWN0IGxpc3RfaGVhZCAgICAgICAgcGRf
bGlzdDsNCj4gPj4gICAgICAgc3RydWN0IGxpc3RfaGVhZCAgICAgICAgbXJfbGlzdDsNCj4gPj4g
ICAgICAgc3RydWN0IGxpc3RfaGVhZCAgICAgICAgbXdfbGlzdDsNCj4gPj4gQEAgLTEzNDQsNiAr
MTM0NywxMCBAQCBzdHJ1Y3QgaWJfdWNvbnRleHQgew0KPiA+PiAgICAgICBzdHJ1Y3QgbGlzdF9o
ZWFkICAgICAgICByd3FfaW5kX3RibF9saXN0Ow0KPiA+PiAgICAgICBpbnQgICAgICAgICAgICAg
ICAgICAgICBjbG9zaW5nOw0KPiA+Pg0KPiA+PiArICAgICAvKiBsb2NrIGZvciB1b2JqZWN0cyBs
aXN0ICovDQo+ID4+ICsgICAgIHN0cnVjdCBpYl91Y29udGV4dF9sb2NrICp1b2JqZWN0c19sb2Nr
Ow0KPiA+PiArICAgICBzdHJ1Y3QgbGlzdF9oZWFkICAgICAgICB1b2JqZWN0czsNCj4gPj4gKw0K
PiA+PiAgICAgICBzdHJ1Y3QgcGlkICAgICAgICAgICAgICp0Z2lkOw0KPiA+PiAgI2lmZGVmIENP
TkZJR19JTkZJTklCQU5EX09OX0RFTUFORF9QQUdJTkcNCj4gPj4gICAgICAgc3RydWN0IHJiX3Jv
b3QgICAgICB1bWVtX3RyZWU7DQo+ID4+IEBAIC0xMzYzLDE2ICsxMzcwLDI4IEBAIHN0cnVjdCBp
Yl91Y29udGV4dCB7DQo+ID4+ICAjZW5kaWYNCj4gPj4gIH07DQo+ID4+DQo+ID4+ICtzdHJ1Y3Qg
dXZlcmJzX29iamVjdF9saXN0Ow0KPiA+PiArDQo+ID4+ICsjZGVmaW5lIE9MRF9BQklfQ09NUEFU
DQo+ID4+ICsNCj4gPj4gIHN0cnVjdCBpYl91b2JqZWN0IHsNCj4gPj4gICAgICAgdTY0ICAgICAg
ICAgICAgICAgICAgICAgdXNlcl9oYW5kbGU7ICAgIC8qIGhhbmRsZSBnaXZlbiB0byB1cw0KPiBi
eSB1c2Vyc3BhY2UNCj4gPj4gKi8NCj4gPj4gICAgICAgc3RydWN0IGliX3Vjb250ZXh0ICAgICAq
Y29udGV4dDsgICAgICAgIC8qIGFzc29jaWF0ZWQgdXNlcg0KPiBjb250ZXh0DQo+ID4+ICovDQo+
ID4+ICAgICAgIHZvaWQgICAgICAgICAgICAgICAgICAgKm9iamVjdDsgICAgICAgICAvKiBjb250
YWluaW5nIG9iamVjdA0KPiAqLw0KPiA+PiAgICAgICBzdHJ1Y3QgbGlzdF9oZWFkICAgICAgICBs
aXN0OyAgICAgICAgICAgLyogbGluayB0byBjb250ZXh0J3MNCj4gbGlzdCAqLw0KPiA+PiAtICAg
ICBpbnQgICAgICAgICAgICAgICAgICAgICBpZDsgICAgICAgICAgICAgLyogaW5kZXggaW50byBr
ZXJuZWwNCj4gaWRyICovDQo+ID4+IC0gICAgIHN0cnVjdCBrcmVmICAgICAgICAgICAgIHJlZjsN
Cj4gPj4gLSAgICAgc3RydWN0IHJ3X3NlbWFwaG9yZSAgICAgbXV0ZXg7ICAgICAgICAgIC8qIHBy
b3RlY3RzIC5saXZlICovDQo+ID4+ICsgICAgIGludCAgICAgICAgICAgICAgICAgICAgIGlkOyAg
ICAgICAgICAgICAvKiBpbmRleCBpbnRvIGtlcm5lbA0KPiBpZHIvZmQgKi8NCj4gPj4gKyNpZmRl
ZiBPTERfQUJJX0NPTVBBVA0KPiA+PiArICAgICBzdHJ1Y3Qga3JlZiAgICAgICAgICAgICByZWY7
DQo+ID4+ICsjZW5kaWYNCj4gPj4gKyAgICAgc3RydWN0IHJ3X3NlbWFwaG9yZSAgICAgdXNlY250
OyAgICAgICAgIC8qIHByb3RlY3RzIGV4Y2x1c2l2ZQ0KPiA+PiBhY2Nlc3MgKi8NCj4gPj4gKyNp
ZmRlZiBPTERfQUJJX0NPTVBBVA0KPiA+PiArICAgICBzdHJ1Y3Qgcndfc2VtYXBob3JlICAgICBt
dXRleDsgICAgICAgICAgLyogcHJvdGVjdHMgLmxpdmUgKi8NCj4gPj4gKyNlbmRpZg0KPiA+PiAg
ICAgICBzdHJ1Y3QgcmN1X2hlYWQgICAgICAgICByY3U7ICAgICAgICAgICAgLyoga2ZyZWVfcmN1
KCkNCj4gb3ZlcmhlYWQgKi8NCj4gPj4gICAgICAgaW50ICAgICAgICAgICAgICAgICAgICAgbGl2
ZTsNCj4gPj4gKw0KPiA+PiArICAgICBjb25zdCBzdHJ1Y3QgdXZlcmJzX3R5cGVfYWxsb2NfYWN0
aW9uICp0eXBlOw0KPiA+PiArICAgICBzdHJ1Y3QgaWJfdWNvbnRleHRfbG9jayAqdW9iamVjdHNf
bG9jazsNCj4gPj4gIH07DQo+ID4+DQo+ID4+ICBzdHJ1Y3QgaWJfdWRhdGEgew0KPiA+PiBAQCAt
MjEwMSw2ICsyMTIwLDkgQEAgc3RydWN0IGliX2RldmljZSB7DQo+ID4+ICAgICAgICAqLw0KPiA+
PiAgICAgICBpbnQgKCpnZXRfcG9ydF9pbW11dGFibGUpKHN0cnVjdCBpYl9kZXZpY2UgKiwgdTgs
IHN0cnVjdA0KPiA+PiBpYl9wb3J0X2ltbXV0YWJsZSAqKTsNCj4gPj4gICAgICAgdm9pZCAoKmdl
dF9kZXZfZndfc3RyKShzdHJ1Y3QgaWJfZGV2aWNlICosIGNoYXIgKnN0ciwgc2l6ZV90DQo+ID4+
IHN0cl9sZW4pOw0KPiA+PiArICAgICBzdHJ1Y3QgbGlzdF9oZWFkIHR5cGVfbGlzdDsNCj4gPj4g
Kw0KPiA+PiArICAgICBjb25zdCBzdHJ1Y3QgdXZlcmJzX3R5cGVzX2dyb3VwICp0eXBlc19ncm91
cDsNCj4gPj4gIH07DQo+ID4+DQo+ID4+ICBzdHJ1Y3QgaWJfY2xpZW50IHsNCj4gPj4gZGlmZiAt
LWdpdCBhL2luY2x1ZGUvcmRtYS91dmVyYnNfaW9jdGwuaA0KPiBiL2luY2x1ZGUvcmRtYS91dmVy
YnNfaW9jdGwuaA0KPiA+PiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+PiBpbmRleCAwMDAwMDAw
Li4yZjUwMDQ1DQo+ID4+IC0tLSAvZGV2L251bGwNCj4gPj4gKysrIGIvaW5jbHVkZS9yZG1hL3V2
ZXJic19pb2N0bC5oDQo+ID4+IEBAIC0wLDAgKzEsMTk1IEBADQo+ID4+ICsvKg0KPiA+PiArICog
Q29weXJpZ2h0IChjKSAyMDE2LCBNZWxsYW5veCBUZWNobm9sb2dpZXMgaW5jLiAgQWxsIHJpZ2h0
cw0KPiA+PiByZXNlcnZlZC4NCj4gPj4gKyAqDQo+ID4+ICsgKiBUaGlzIHNvZnR3YXJlIGlzIGF2
YWlsYWJsZSB0byB5b3UgdW5kZXIgYSBjaG9pY2Ugb2Ygb25lIG9mIHR3bw0KPiA+PiArICogbGlj
ZW5zZXMuICBZb3UgbWF5IGNob29zZSB0byBiZSBsaWNlbnNlZCB1bmRlciB0aGUgdGVybXMgb2Yg
dGhlDQo+IEdOVQ0KPiA+PiArICogR2VuZXJhbCBQdWJsaWMgTGljZW5zZSAoR1BMKSBWZXJzaW9u
IDIsIGF2YWlsYWJsZSBmcm9tIHRoZSBmaWxlDQo+ID4+ICsgKiBDT1BZSU5HIGluIHRoZSBtYWlu
IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLCBvciB0aGUNCj4gPj4gKyAqIE9wZW5JQi5v
cmcgQlNEIGxpY2Vuc2UgYmVsb3c6DQo+ID4+ICsgKg0KPiA+PiArICogICAgIFJlZGlzdHJpYnV0
aW9uIGFuZCB1c2UgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3INCj4gPj4gKyAq
ICAgICB3aXRob3V0IG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRo
ZQ0KPiBmb2xsb3dpbmcNCj4gPj4gKyAqICAgICBjb25kaXRpb25zIGFyZSBtZXQ6DQo+ID4+ICsg
Kg0KPiA+PiArICogICAgICAtIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJl
dGFpbiB0aGUgYWJvdmUNCj4gPj4gKyAqICAgICAgICBjb3B5cmlnaHQgbm90aWNlLCB0aGlzIGxp
c3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlDQo+IGZvbGxvd2luZw0KPiA+PiArICogICAgICAgIGRp
c2NsYWltZXIuDQo+ID4+ICsgKg0KPiA+PiArICogICAgICAtIFJlZGlzdHJpYnV0aW9ucyBpbiBi
aW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUNCj4gPj4gKyAqICAgICAgICBjb3B5
cmlnaHQgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlDQo+IGZvbGxvd2lu
Zw0KPiA+PiArICogICAgICAgIGRpc2NsYWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29y
IG90aGVyIG1hdGVyaWFscw0KPiA+PiArICogICAgICAgIHByb3ZpZGVkIHdpdGggdGhlIGRpc3Ry
aWJ1dGlvbi4NCj4gPj4gKyAqDQo+ID4+ICsgKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFT
IElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwNCj4gPj4gKyAqIEVYUFJFU1MgT1Ig
SU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUw0KPiBP
Rg0KPiA+PiArICogTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVS
UE9TRSBBTkQNCj4gPj4gKyAqIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhF
IEFVVEhPUlMgT1IgQ09QWVJJR0hUDQo+IEhPTERFUlMNCj4gPj4gKyAqIEJFIExJQUJMRSBGT1Ig
QU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTg0KPiBBTg0K
PiA+PiArICogQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBG
Uk9NLCBPVVQgT0YgT1INCj4gSU4NCj4gPj4gKyAqIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdB
UkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUNCj4gPj4gKyAqIFNPRlRXQVJF
Lg0KPiA+PiArICovDQo+ID4+ICsNCj4gPj4gKyNpZm5kZWYgX1VWRVJCU19JT0NUTF8NCj4gPj4g
KyNkZWZpbmUgX1VWRVJCU19JT0NUTF8NCj4gPj4gKw0KPiA+PiArI2luY2x1ZGUgPGxpbnV4L2tl
cm5lbC5oPg0KPiA+PiArDQo+ID4+ICtzdHJ1Y3QgdXZlcmJzX29iamVjdF90eXBlOw0KPiA+PiAr
c3RydWN0IGliX3Vjb250ZXh0Ow0KPiA+PiArc3RydWN0IGliX3VvYmplY3Q7DQo+ID4+ICtzdHJ1
Y3QgaWJfZGV2aWNlOw0KPiA+PiArc3RydWN0IHV2ZXJic191b2JqZWN0X3R5cGU7DQo+ID4+ICsN
Cj4gPj4gKy8qDQo+ID4+ICsgKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT0NCj4gPj4gKyAqICAgVmVyYnMgYWN0aW9uIHNwZWNpZmljYXRpb25zDQo+ID4+ICsgKiA9PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCj4gPj4gKyAqLw0KPiA+DQo+ID4g
SSBpbnRlbnRpb25hbGx5IHVzZWQgdXJkbWEgKHRob3VnaCBjb25kZW5zZWQgdG8gMyBsZXR0ZXJz
IHRoYXQgSQ0KPiBkb24ndCByZWNhbGwgYXRtKSwgcmF0aGVyIHRoYW4gdXZlcmJzLiAgVGhpcyB3
aWxsIG5lZWQgdG8gd29yayB3aXRoDQo+IG5vbi12ZXJicyBkZXZpY2VzIGFuZCBpbnRlcmZhY2Vz
IC0tIGFnYWluLCBjb25zaWRlciBob3cgdGhpcyBmaXRzIHdpdGgNCj4gdGhlIHJkbWEgY20uICBW
ZXJicyBoYXMgYSB2ZXJ5IHNwZWNpZmljIG1lYW5pbmcsIHdoaWNoIGdldHMgbG9zdCBpZiB3ZQ0K
PiBzdGFydCByZWZlcnJpbmcgdG8gZXZlcnl0aGluZyBhcyAndmVyYnMnLiAgSXQncyBiYWQgZW5v
dWdoIHRoYXQgd2UncmUNCj4gc3R1Y2sgd2l0aCAnZHJpdmVycy9pbmZpbmliYW5kJyBhbmQgJ3Jk
bWEnLCBzdWNoIHRoYXQgJ2luZmluaWJhbmQnIGFsc28NCj4gbWVhbnMgZXRoZXJuZXQgYW5kIHJk
bWEgbWVhbnMgbm90aGluZy4NCj4gPg0KPiANCj4gSU1ITyAtIGxldCdzIGFncmVlIG9uIHRoZSBj
b25jZXB0IG9mIHRoaXMgaW5mcmFzdHJ1Y3R1cmUuIE9uZSB3ZQ0KPiBkZWNpZGUgaXRzIHNjb3Bl
LCB3ZSBjb3VsZCBnZW5lcmFsaXplIGl0IChpLmUgLSBpb2N0bF9wcm92aWRlciBhbmQNCj4gaW9j
dGxfY29udGV4dCkgYW5kIGltcGxlbWVudCBpdCB0byByZG1hLWNtIGFzIHdlbGwuDQo+IA0KPiA+
PiArDQo+ID4+ICtlbnVtIHV2ZXJic19hdHRyX3R5cGUgew0KPiA+PiArICAgICBVVkVSQlNfQVRU
Ul9UWVBFX1BUUl9JTiwNCj4gPj4gKyAgICAgVVZFUkJTX0FUVFJfVFlQRV9QVFJfT1VULA0KPiA+
PiArICAgICBVVkVSQlNfQVRUUl9UWVBFX0lEUiwNCj4gPj4gKyAgICAgVVZFUkJTX0FUVFJfVFlQ
RV9GRCwNCj4gPj4gK307DQo+ID4+ICsNCj4gPj4gK2VudW0gdXZlcmJzX2lkcl9hY2Nlc3Mgew0K
PiA+PiArICAgICBVVkVSQlNfSURSX0FDQ0VTU19SRUFELA0KPiA+PiArICAgICBVVkVSQlNfSURS
X0FDQ0VTU19XUklURSwNCj4gPj4gKyAgICAgVVZFUkJTX0lEUl9BQ0NFU1NfTkVXLA0KPiA+PiAr
ICAgICBVVkVSQlNfSURSX0FDQ0VTU19ERVNUUk9ZDQo+ID4+ICt9Ow0KPiA+PiArDQo+ID4+ICtz
dHJ1Y3QgdXZlcmJzX2F0dHJfc3BlYyB7DQo+ID4+ICsgICAgIHUxNiAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgbGVuOw0KPiA+PiArICAgICBlbnVtIHV2ZXJic19hdHRyX3R5cGUgICAgICAg
ICAgIHR5cGU7DQo+ID4+ICsgICAgIHN0cnVjdCB7DQo+ID4+ICsgICAgICAgICAgICAgdTE2ICAg
ICAgICAgICAgICAgICAgICAgb2JqX3R5cGU7DQo+ID4+ICsgICAgICAgICAgICAgdTggICAgICAg
ICAgICAgICAgICAgICAgYWNjZXNzOw0KPiA+DQo+ID4gSXMgYWNjZXNzIGludGVuZGVkIHRvIGJl
IGFuIGVudW0gdXZlcmJzX2lkcl9hY2Nlc3MgdmFsdWU/DQo+ID4NCj4gDQo+IFllYWgsIHdvcnRo
IHVzaW5nIHRoaXMgZW51bS4gVGhhbmtzLg0KPiANCj4gPj4gKyAgICAgfSBvYmo7DQo+ID4NCj4g
PiBJIHdvdWxkIHJlbW92ZSAoZmxhdHRlbikgdGhlIHN1YnN0cnVjdHVyZSBhbmQgcmUtb3JkZXIg
dGhlIGZpZWxkcyBmb3INCj4gYmV0dGVyIGFsaWdubWVudC4NCj4gPg0KPiANCj4gSSBub3RpY2Vk
IHRoZXJlIGFyZSBzZXZlcmFsIHBsYWNlcyB3aGljaCBhcmVuJ3QgYWxpZ2VkLiBJdCdzIGluIG15
IHRvZG8NCj4gbGlzdC4NCj4gDQo+ID4+ICt9Ow0KPiA+PiArDQo+ID4+ICtzdHJ1Y3QgdXZlcmJz
X2F0dHJfZ3JvdXBfc3BlYyB7DQo+ID4+ICsgICAgIHN0cnVjdCB1dmVyYnNfYXR0cl9zcGVjICAg
ICAgICAgKmF0dHJzOw0KPiA+PiArICAgICBzaXplX3QgICAgICAgICAgICAgICAgICAgICAgICAg
IG51bV9hdHRyczsNCj4gPj4gK307DQo+ID4+ICsNCj4gPj4gK3N0cnVjdCB1dmVyYnNfYWN0aW9u
X3NwZWMgew0KPiA+PiArICAgICBjb25zdCBzdHJ1Y3QgdXZlcmJzX2F0dHJfZ3JvdXBfc3BlYyAg
ICAgICAgICAgICAqKmF0dHJfZ3JvdXBzOw0KPiA+PiArICAgICAvKiBpZiA+IDAgLT4gdmFsaWRh
dG9yLCBvdGhlcndpc2UsIGVycm9yICovDQo+ID4NCj4gPiA/IG5vdCBzdXJlIHdoYXQgdGhpcyBj
b21tZW50IG1lYW5zDQo+ID4NCj4gPj4gKyAgICAgaW50ICgqZGlzdCkoX191MTYgKmF0dHJfaWQs
IHZvaWQgKnByaXYpOw0KPiA+DQo+ID4gV2hhdCBkb2VzICdkaXN0JyBzdGFuZCBmb3I/DQo+ID4N
Cj4gDQo+IGRpc3QgPSBkaXN0cmlidXRpb24gZnVuY3Rpb24uDQo+IEl0IG1hcHMgdGhlIGF0dHJp
YnV0ZXMgeW91IGdvdCBmcm9tIHRoZSB1c2VyLXNwYWNlIHRvIHlvdXIgZ3JvdXBzLiBZb3UNCj4g
Y291bGQgdGhpbmsgb2YgZWFjaCBncm91cCBhcyBhIG5hbWVzcGFjZSAtIHdoZXJlIGl0cyBhdHRy
aWJ1dGVzIChvcg0KPiB0eXBlcy9hY3Rpb25zKSBzdGFydHMgZnJvbSB6ZXJvIGluIHRoZSBzYWtl
IG9mIGNvbXBhY3RuZXNzLg0KPiBTbywgZm9yIGV4YW1wbGUsIGl0IGdldHMgYW4gYXR0cmlidXRl
IDB4ODAxMCBhbmQgbWFwcyB0byB0byAiZ3JvdXAgMSINCj4gKHByb3ZpZGVyKSBhbmQgYXR0cmli
dXRlIDB4MTAuDQo+IA0KPiA+PiArICAgICB2b2lkICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAqcHJpdjsNCj4gPj4gKyAgICAgc2l6ZV90ICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtX2dyb3VwczsNCj4gPj4gK307DQo+ID4+ICsN
Cj4gPj4gK3N0cnVjdCB1dmVyYnNfYXR0cl9hcnJheTsNCj4gPj4gK3N0cnVjdCBpYl91dmVyYnNf
ZmlsZTsNCj4gPj4gKw0KPiA+PiArc3RydWN0IHV2ZXJic19hY3Rpb24gew0KPiA+PiArICAgICBz
dHJ1Y3QgdXZlcmJzX2FjdGlvbl9zcGVjIHNwZWM7DQo+ID4+ICsgICAgIHZvaWQgKnByaXY7DQo+
ID4+ICsgICAgIGludCAoKmhhbmRsZXIpKHN0cnVjdCBpYl9kZXZpY2UgKmliX2Rldiwgc3RydWN0
IGliX3V2ZXJic19maWxlDQo+ID4+ICp1ZmlsZSwNCj4gPj4gKyAgICAgICAgICAgICAgICAgICAg
c3RydWN0IHV2ZXJic19hdHRyX2FycmF5ICpjdHgsIHNpemVfdCBudW0sIHZvaWQNCj4gPj4gKnBy
aXYpOw0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArc3RydWN0IHV2ZXJic190eXBlX2FsbG9jX2Fj
dGlvbjsNCj4gPj4gK3R5cGVkZWYgdm9pZCAoKmZyZWVfdHlwZSkoY29uc3Qgc3RydWN0IHV2ZXJi
c190eXBlX2FsbG9jX2FjdGlvbg0KPiA+PiAqdW9iamVjdF90eXBlLA0KPiA+PiArICAgICAgICAg
ICAgICAgICAgICAgICBzdHJ1Y3QgaWJfdW9iamVjdCAqdW9iamVjdCk7DQo+ID4+ICsNCj4gPj4g
K3N0cnVjdCB1dmVyYnNfdHlwZV9hbGxvY19hY3Rpb24gew0KPiA+PiArICAgICBlbnVtIHV2ZXJi
c19hdHRyX3R5cGUgICAgICAgICAgIHR5cGU7DQo+ID4+ICsgICAgIGludCAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgb3JkZXI7DQo+ID4NCj4gPiBJIHRoaW5rIHRoaXMgaXMgYmVpbmcgdXNl
ZCBhcyBkZXN0cm95IG9yZGVyLCBpbiB3aGljaCBjYXNlIEkgd291bGQNCj4gcmVuYW1lIGl0IHRv
IGNsYXJpZnkgdGhlIGludGVudC4gIFRob3VnaCBJJ2QgcHJlZmVyIHdlIGNvbWUgdXAgd2l0aCBh
DQo+IG1vcmUgZWZmaWNpZW50IGRlc3RydWN0aW9uIG1lY2hhbmlzbSB0aGFuIHRoZSByZXBlYXRl
ZCBuZXN0ZWQgbG9vcGluZy4NCj4gPg0KPiANCj4gSW4gb25lIG9mIHRoZSBlYXJsaWVyIHJldmlz
aW9ucyBJIHVzZWQgYSBzb3J0ZWQgbGlzdCwgd2hpY2ggd2FzDQo+IGVmZmljaWVudC4gSSByZWNh
bGwgdGhhdCBKYXNvbiBkaWRuJ3QgbGlrZSBpdHMgY29tcGxleGl0eSBhbmQNCj4gcmUtdGhpbmtp
bmcgYWJvdXQgdGhhdCAtIGhlJ3MgcmlnaHQuIE1vc3Qgb2YgeW91ciB0eXBlcyBhcmUgIm9yZGVy
DQo+IG51bWJlciIgMCBhbnl3YXkuIFNvIHlvdSdsbCBwcm9iYWJseSBpdGVyYXRlIHZlcnkgZmV3
IG9iamVjdHMgaW4gdGhlDQo+IG5leHQgcm91bmQgKGluIHZlcmJzLCBldmVyeXRoaW5nIGJ1dCBN
UnMgYW5kIFBEcykuDQo+IA0KPiA+PiArICAgICBzaXplX3QgICAgICAgICAgICAgICAgICAgICAg
ICAgIG9ial9zaXplOw0KPiA+DQo+ID4gVGhpcyBjYW4gYmUgYWxsb2NfZm4NCj4gPg0KPiA+PiAr
ICAgICBmcmVlX3R5cGUgICAgICAgICAgICAgICAgICAgICAgIGZyZWVfZm47DQo+ID4+ICsgICAg
IHN0cnVjdCB7DQo+ID4+ICsgICAgICAgICAgICAgY29uc3Qgc3RydWN0IGZpbGVfb3BlcmF0aW9u
cyAgICAqZm9wczsNCj4gPj4gKyAgICAgICAgICAgICBjb25zdCBjaGFyICAgICAgICAgICAgICAg
ICAgICAgICpuYW1lOw0KPiA+PiArICAgICAgICAgICAgIGludCAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgZmxhZ3M7DQo+ID4+ICsgICAgIH0gZmQ7DQo+ID4+ICt9Ow0KPiA+PiArDQo+ID4+
ICtzdHJ1Y3QgdXZlcmJzX3R5cGVfYWN0aW9uc19ncm91cCB7DQo+ID4+ICsgICAgIHNpemVfdCAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1fYWN0aW9uczsNCj4gPj4gKyAgICAg
Y29uc3Qgc3RydWN0IHV2ZXJic19hY3Rpb24gICAgICAgICAgICAgICoqYWN0aW9uczsNCj4gPj4g
K307DQo+ID4+ICsNCj4gPj4gK3N0cnVjdCB1dmVyYnNfdHlwZSB7DQo+ID4+ICsgICAgIHNpemVf
dCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1fZ3JvdXBzOw0KPiA+PiArICAg
ICBjb25zdCBzdHJ1Y3QgdXZlcmJzX3R5cGVfYWN0aW9uc19ncm91cCAgKiphY3Rpb25fZ3JvdXBz
Ow0KPiA+PiArICAgICBjb25zdCBzdHJ1Y3QgdXZlcmJzX3R5cGVfYWxsb2NfYWN0aW9uICAgKmFs
bG9jOw0KPiA+PiArICAgICBpbnQgKCpkaXN0KShfX3UxNiAqYWN0aW9uX2lkLCB2b2lkICpwcml2
KTsNCj4gPj4gKyAgICAgdm9pZCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICpw
cml2Ow0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArc3RydWN0IHV2ZXJic190eXBlcyB7DQo+ID4+
ICsgICAgIHNpemVfdCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1fdHlwZXM7
DQo+ID4+ICsgICAgIGNvbnN0IHN0cnVjdCB1dmVyYnNfdHlwZSAgICAgICAgICAgICAgICAqKnR5
cGVzOw0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArc3RydWN0IHV2ZXJic190eXBlc19ncm91cCB7
DQo+ID4+ICsgICAgIGNvbnN0IHN0cnVjdCB1dmVyYnNfdHlwZXMgICAgICAgICAgICAgICAqKnR5
cGVfZ3JvdXBzOw0KPiA+PiArICAgICBzaXplX3QgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgbnVtX2dyb3VwczsNCj4gPj4gKyAgICAgaW50ICgqZGlzdCkoX191MTYgKnR5cGVfaWQs
IHZvaWQgKnByaXYpOw0KPiA+PiArICAgICB2b2lkICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgKnByaXY7DQo+ID4+ICt9Ow0KPiA+PiArDQo+ID4+ICsvKiA9PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQo+ID4+ICsgKiAgICAgICAgICAg
ICAgUGFyc2luZyBpbmZyYXN0cnVjdHVyZQ0KPiA+PiArICogPT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KPiA+PiArICovDQo+ID4+ICsNCj4gPj4gK3N0
cnVjdCB1dmVyYnNfcHRyX2F0dHIgew0KPiA+PiArICAgICB2b2lkICAgICogX191c2VyIHB0cjsN
Cj4gPj4gKyAgICAgX191MTYgICAgICAgICAgIGxlbjsNCj4gPj4gK307DQo+ID4+ICsNCj4gPj4g
K3N0cnVjdCB1dmVyYnNfZmRfYXR0ciB7DQo+ID4+ICsgICAgIGludCAgICAgICAgICAgICBmZDsN
Cj4gPj4gK307DQo+ID4+ICsNCj4gPj4gK3N0cnVjdCB1dmVyYnNfdW9ial9hdHRyIHsNCj4gPj4g
KyAgICAgLyogIGlkciBoYW5kbGUgKi8NCj4gPj4gKyAgICAgX191MzIgICBpZHI7DQo+ID4+ICt9
Ow0KPiA+PiArDQo+ID4+ICtzdHJ1Y3QgdXZlcmJzX29ial9hdHRyIHsNCj4gPj4gKyAgICAgLyog
cG9pbnRlciB0byB0aGUga2VybmVsIGRlc2NyaXB0b3IgLT4gdHlwZSwgYWNjZXNzLCBldGMgKi8N
Cj4gPj4gKyAgICAgY29uc3Qgc3RydWN0IHV2ZXJic19hdHRyX3NwZWMgKnZhbDsNCj4gPj4gKyAg
ICAgc3RydWN0IGliX3V2ZXJic19hdHRyIF9fdXNlciAgICAqdWF0dHI7DQo+ID4+ICsgICAgIGNv
bnN0IHN0cnVjdCB1dmVyYnNfdHlwZV9hbGxvY19hY3Rpb24gICAqdHlwZTsNCj4gPj4gKyAgICAg
c3RydWN0IGliX3VvYmplY3QgICAgICAgICAgICAgICAqdW9iamVjdDsNCj4gPj4gKyAgICAgdW5p
b24gew0KPiA+PiArICAgICAgICAgICAgIHN0cnVjdCB1dmVyYnNfZmRfYXR0ciAgICAgICAgICAg
ZmQ7DQo+ID4+ICsgICAgICAgICAgICAgc3RydWN0IHV2ZXJic191b2JqX2F0dHIgICAgICAgICB1
b2JqOw0KPiA+PiArICAgICB9Ow0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArc3RydWN0IHV2ZXJi
c19hdHRyIHsNCj4gPj4gKyAgICAgYm9vbCB2YWxpZDsgPiA+PiArICAgICB1bmlvbiB7DQo+ID4+
ICsgICAgICAgICAgICAgc3RydWN0IHV2ZXJic19wdHJfYXR0ciAgY21kX2F0dHI7DQo+ID4+ICsg
ICAgICAgICAgICAgc3RydWN0IHV2ZXJic19vYmpfYXR0ciAgb2JqX2F0dHI7DQo+ID4+ICsgICAg
IH07DQo+ID4+ICt9Ow0KPiA+DQo+ID4gSXQncyBvZGQgdG8gaGF2ZSBhIHVuaW9uIHRoYXQncyBw
YXJ0IG9mIGEgc3RydWN0dXJlIHdpdGhvdXQgc29tZQ0KPiBmaWVsZCB0byBpbmRpY2F0ZSB3aGlj
aCB1bmlvbiBmaWVsZCBpcyBhY2Nlc3NpYmxlLg0KPiA+DQo+IA0KPiBZb3UgaW5kZXggdGhpcyBh
cnJheSBidXQgdGhlIGF0dHJpYnV0ZSBpZCBmcm9tIHRoZSB1c2VyJ3MgY2FsbGJhY2sNCj4gZnVu
Y2l0b24uIFRoZSB1c2VyIHNob3VsZCBrbm93IHdoYXQncyB0aGUgdHlwZSBvZiB0aGUgYXR0cmli
dXRlLCBhcw0KPiBbc11oZSBkZWNsYXJlZCB0aGUgc3BlY2lmaWNhdGlvbi4NCj4gDQo+ID4+ICsN
Cj4gPj4gKy8qIG91dHB1dCBvZiBvbmUgdmFsaWRhdG9yICovDQo+ID4+ICtzdHJ1Y3QgdXZlcmJz
X2F0dHJfYXJyYXkgew0KPiA+PiArICAgICBzaXplX3QgbnVtX2F0dHJzOw0KPiA+PiArICAgICAv
KiBhcnJheXMgb2YgYXR0cnVieXRlcywgaW5kZXggaXMgdGhlIGlkIGkuZSBTRU5EX0NRICovDQo+
ID4+ICsgICAgIHN0cnVjdCB1dmVyYnNfYXR0ciAqYXR0cnM7DQo+ID4+ICt9Ow0KPiA+PiArDQo+
ID4+ICsvKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
DQo+ID4+ICsgKiAgICAgICAgICAgICAgVHlwZXMgaW5mcmFzdHJ1Y3R1cmUNCj4gPj4gKyAqID09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCj4gPj4gKyAq
Lw0KPiA+PiArDQo+ID4+ICtpbnQgaWJfdXZlcmJzX3VvYmplY3RfdHlwZV9hZGQoc3RydWN0IGxp
c3RfaGVhZCAgICAgICpoZWFkLA0KPiA+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZv
aWQgKCpmcmVlKShzdHJ1Y3QgdXZlcmJzX3VvYmplY3RfdHlwZQ0KPiAqdHlwZSwNCj4gPj4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RydWN0IGliX3VvYmplY3QN
Cj4gKnVvYmplY3QsDQo+ID4+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIHN0cnVjdCBpYl91Y29udGV4dA0KPiAqdWNvbnRleHQpLA0KPiA+PiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIHVpbnQxNl90IG9ial90eXBlKTsNCj4gPj4gK3ZvaWQgaWJfdXZlcmJz
X3VvYmplY3RfdHlwZXNfcmVtb3ZlKHN0cnVjdCBpYl9kZXZpY2UgKmliX2Rldik7DQo+ID4+ICsN
Cj4gPj4gKyNlbmRpZg0KPiA+PiAtLQ0KPiA+PiAyLjcuNA0KDQpNYXRhbiwgcGxlYXNlIHJlLWxv
b2sgYXQgdGhlIGFyY2hpdGVjdHVyZSB0aGF0IEkgcHJvcG9zZWQ6DQoNCmh0dHBzOi8vcGF0Y2h3
b3JrLmtlcm5lbC5vcmcvcGF0Y2gvOTE3ODk5MS8NCg0KaW5jbHVkaW5nIHRoZSB0ZXJtaW5vbG9n
eSAoYW5kIGNvbnNpZGVyIHVzaW5nIGNvbW1vbiBPT1AgdGVybXMpLiAgVGhlICpjb3JlKiBvZiB0
aGUgaW9jdGwgZnJhbWV3b3JrIGlzIHRvIHNpbXBseSBpbnZva2UgYSBmdW5jdGlvbiBkaXNwYXRj
aCB0YWJsZS4gIElNTywgdGhhdCdzIHdoZXJlIHdlIHNob3VsZCBzdGFydC4gIEFueXRoaW5nIGJl
eW9uZCB0aGF0IGlzIGV4dHJhIHRoYXQgd2Ugc2hvdWxkIGhhdmUgYSBzdHJvbmcgcmVhc29uIGZv
ciBpbmNsdWRpbmcuICAoWWVzLCBJIHRoaW5rIHdlIG5lZWQgbW9yZS4pICBTdGFydGluZyBzaW1w
bGUgYW5kIGFkZGluZyBuZWNlc3NhcnkgZnVuY3Rpb25hbGl0eSBzaG91bGQgbGV0IHVzIGdldCBz
b21ldGhpbmcgdXBzdHJlYW0gcXVpY2tlciBhbmQgcmUtdXNlIG1vcmUgb2YgdGhlIGV4aXN0aW5n
IGNvZGUuDQoNCklmIHdlJ3JlIGdvaW5nIHRvIHJlLWNyZWF0ZSBuZXRsaW5rIGFzIHBhcnQgb2Yg
dGhlIHJkbWEgaW9jdGwgaW50ZXJmYWNlLCB0aGVuIHdoeSBkb24ndCB3ZSBqdXN0IHVzZSBuZXRs
aW5rIGRpcmVjdGx5Pw0K
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe Nov. 9, 2016, 6:50 p.m. UTC | #4
On Wed, Nov 09, 2016 at 06:00:48PM +0000, Hefty, Sean wrote:

> In any case, the two approaches are not exclusive.  By forcing the
> rule language into the framework, everything is forced to deal with
> it.  By leaving it out, each ioctl provider can decide if they need
> this or not.  If you want verbs to process all ioctl's using a
> single pre-validation function that operates based on these rules
> you can.  Nothing prevents that.  But ioctl providers that want
> better performance can elect for a more straightforward validation
> model.

The pre-validation is tied into the hash expansion and will hopefully
be the raw data to support a new discoverability scheme. So, making it
optional really wrecks the whole design, I think.

Also, this is really the best way to ensure that we have consistent
checking and error reporting around attributes (eg what happens if the
kernel does not support a requested attribute, or uses the wrong size,
etc) It is very important these things use the correct errnos not the
random mismatch we see today.

I'm not seeing that it is a clear peformance loss (relative to open
coding at least), the major work is the expansion to the hash table
and doing a couple size tests along the way is not hard. Matan's
revised series should be event better on this regard as I gave alot
of feedback to speed it up at plumbers.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Matan Barak Nov. 10, 2016, 8:29 a.m. UTC | #5
On 09/11/2016 20:00, Hefty, Sean wrote:
>> I had thought about that, but the user could initialize its part of
>> the object in the function handler. It can't allocate the object as we
>> need it in order to allocate an IDR entry and co. The assumption here
>> is that the "unlock" stage can't fail.
>
> This is creating a generic OO type of framework, so just add constructor/destructor functions and have all objects inherit from a base ioctl object class.
>

Adding a constructor and destructor to every object would make the 
infrastructure slower, it'll open code the locks (which are more related 
to the actions themselves and not to the types), it'll duplicate more 
code. Anyway, examining our use, I don't really see good value for ctors 
and dtors for our usage right now.

>>> In fact, it would be great if we could just cleanup the list in the
>> reverse order that items were created.  Maybe this requires supporting
>> a pre-cleanup handler, so that the driver can pluck items out of the
>> list that may need to be destroyed out of order.
>>>
>>
>> So that's essentially one layer of ordering. Why do you consider a
>> driver iterating over all objects simpler than this model?
>
> This problem is a verbs specific issue, and one that only involves MW .  We have reference counts that can provide the same functionality.  I want to avoid the amount of meta-data that needs to be used to describe objects.
>

It's currently happens in the verbs MW/MRs. However, it could happen 
with any types whose bindings happen in the user-space or hardware.

>>>> Adding an object is done in two parts.
>>>> First, an object is allocated and added to IDR/fd table. Then, the
>>>> command's handlers (in downstream patches) could work on this object
>>>> and fill in its required details.
>>>> After a successful command, ib_uverbs_uobject_enable is called and
>>>> this user objects becomes ucontext visible.
>>>
>>> If you have a way to mark that an object is used for exclusive
>> access, you may be able to use that instead of introducing a new
>> variable.  (I.e. acquire the object's write lock).  I think we want to
>> make an effort to minimize the size of the kernel structure needed to
>> track every user space object (within reason).
>>>
>>
>> I didn't really follow. A command attribute states the nature of the
>> locking (for example, in MODIFY_QP the QP could be exclusively locked,
>> but in QUERY_QP it's only locked for reading). I don't want to really
>> grab a lock, as if I were I could face a dead-lock (user-space could
>> pass parameters in a colliding order), It could be solved by sorting
>> the handles, but that would degrade performance without a good reasob.
>
> I'm suggesting that the locking attribute and command be separate.  This allows the framework to acquire the proper type of lock independent of what function it will invoke.
>

The locking is tied to what you want to do on that type. If you query 
something, read locks are probably enough. I don't think separating them 
will make the code more readable.

> The framework doesn't need to hold locks.  It should be able to mark access to an object.  If that access is not available, it can abort.  This pushes more complex synchronization and thread handling to user space.
>

The try_{read,write} locks achieve exactly that and are simple enough.

>>>> Removing an uboject is done by calling ib_uverbs_uobject_remove.
>>>>
>>>> We should make sure IDR (per-device) and list (per-ucontext) could
>>>> be accessed concurrently without corrupting them.
>>>>
>>>> Signed-off-by: Matan Barak <matanb@mellanox.com>
>>>> Signed-off-by: Haggai Eran <haggaie@mellanox.com>
>>>> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
>>>> ---
>>>
>>> As a general comment, I do have concerns that the resulting
>> generalized parsing of everything will negatively impact performance
>> for operations that do have to transition into the kernel.  Not all
>> devices offload all operations to user space.  Plus the resulting code
>> is extremely difficult to read and non-trivial to use.  It's equivalent
>> to reading C++ code that has 4 layers of inheritance with overrides to
>> basic operators...
>>
>> There are two parts here. I think the handlers themselves are simpler,
>> easier to read and less error-prone. They contain less code
>> duplications. The macro based define language explicitly declare all
>> attributes, their types, size, etc.
>> The model here is a bit more complex as we want to achieve both code
>> resue and add/override of new types/actions/attributes.
>>
>>
>>>
>>> Pre and post operators per command that can do straightforward
>> validation seem like a better option.
>>>
>>>
>>
>> I think that would duplicate a lot of code and will be more
>> error-prone than one infrastrucutre that automates all that work for
>> you.
>
> I think that's a toss-up.  Either you have to write the code correctly or write the rules correctly.  Reading code is straightforward, manually converting rules into code is not.
>
> In any case, the two approaches are not exclusive.  By forcing the rule language into the framework, everything is forced to deal with it.  By leaving it out, each ioctl provider can decide if they need this or not.  If you want verbs to process all ioctl's using a single pre-validation function that operates based on these rules you can.  Nothing prevents that.  But ioctl providers that want better performance can elect for a more straightforward validation model.
>

Please see Jason's response.

>>>>  drivers/infiniband/core/Makefile      |   3 +-
>>>>  drivers/infiniband/core/device.c      |   1 +
>>>>  drivers/infiniband/core/rdma_core.c   | 489
>>>> ++++++++++++++++++++++++++++++++++
>>>>  drivers/infiniband/core/rdma_core.h   |  75 ++++++
>>>>  drivers/infiniband/core/uverbs.h      |   1 +
>>>>  drivers/infiniband/core/uverbs_main.c |   2 +-
>>>>  include/rdma/ib_verbs.h               |  28 +-
>>>>  include/rdma/uverbs_ioctl.h           | 195 ++++++++++++++
>>>>  8 files changed, 789 insertions(+), 5 deletions(-)
>>>>  create mode 100644 drivers/infiniband/core/rdma_core.c
>>>>  create mode 100644 drivers/infiniband/core/rdma_core.h
>>>>  create mode 100644 include/rdma/uverbs_ioctl.h
>>>>
>>>> diff --git a/drivers/infiniband/core/Makefile
>>>> b/drivers/infiniband/core/Makefile
>>>> index edaae9f..1819623 100644
>>>> --- a/drivers/infiniband/core/Makefile
>>>> +++ b/drivers/infiniband/core/Makefile
>>>> @@ -28,4 +28,5 @@ ib_umad-y :=                        user_mad.o
>>>>
>>>>  ib_ucm-y :=                  ucm.o
>>>>
>>>> -ib_uverbs-y :=                       uverbs_main.o uverbs_cmd.o
>>>> uverbs_marshall.o
>>>> +ib_uverbs-y :=                       uverbs_main.o uverbs_cmd.o
>>>> uverbs_marshall.o \
>>>> +                             rdma_core.o
>>>> diff --git a/drivers/infiniband/core/device.c
>>>> b/drivers/infiniband/core/device.c
>>>> index c3b68f5..43994b1 100644
>>>> --- a/drivers/infiniband/core/device.c
>>>> +++ b/drivers/infiniband/core/device.c
>>>> @@ -243,6 +243,7 @@ struct ib_device *ib_alloc_device(size_t size)
>>>>       spin_lock_init(&device->client_data_lock);
>>>>       INIT_LIST_HEAD(&device->client_data_list);
>>>>       INIT_LIST_HEAD(&device->port_list);
>>>> +     INIT_LIST_HEAD(&device->type_list);
>>>>
>>>>       return device;
>>>>  }
>>>> diff --git a/drivers/infiniband/core/rdma_core.c
>>>> b/drivers/infiniband/core/rdma_core.c
>>>> new file mode 100644
>>>> index 0000000..337abc2
>>>> --- /dev/null
>>>> +++ b/drivers/infiniband/core/rdma_core.c
>>>> @@ -0,0 +1,489 @@
>>>> +/*
>>>> + * Copyright (c) 2016, Mellanox Technologies inc.  All rights
>>>> reserved.
>>>> + *
>>>> + * This software is available to you under a choice of one of two
>>>> + * licenses.  You may choose to be licensed under the terms of the
>> GNU
>>>> + * General Public License (GPL) Version 2, available from the file
>>>> + * COPYING in the main directory of this source tree, or the
>>>> + * OpenIB.org BSD license below:
>>>> + *
>>>> + *     Redistribution and use in source and binary forms, with or
>>>> + *     without modification, are permitted provided that the
>> following
>>>> + *     conditions are met:
>>>> + *
>>>> + *      - Redistributions of source code must retain the above
>>>> + *        copyright notice, this list of conditions and the
>> following
>>>> + *        disclaimer.
>>>> + *
>>>> + *      - Redistributions in binary form must reproduce the above
>>>> + *        copyright notice, this list of conditions and the
>> following
>>>> + *        disclaimer in the documentation and/or other materials
>>>> + *        provided with the distribution.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>> OF
>>>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>>>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
>> HOLDERS
>>>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
>> AN
>>>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
>> IN
>>>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>>>> + * SOFTWARE.
>>>> + */
>>>> +
>>>> +#include <linux/file.h>
>>>> +#include <linux/anon_inodes.h>
>>>> +#include <rdma/ib_verbs.h>
>>>> +#include "uverbs.h"
>>>> +#include "rdma_core.h"
>>>> +#include <rdma/uverbs_ioctl.h>
>>>> +
>>>> +const struct uverbs_type *uverbs_get_type(const struct ib_device
>>>> *ibdev,
>>>> +                                       uint16_t type)
>>>> +{
>>>> +     const struct uverbs_types_group *groups = ibdev->types_group;
>>>> +     const struct uverbs_types *types;
>>>> +     int ret = groups->dist(&type, groups->priv);
>>>> +
>>>> +     if (ret >= groups->num_groups)
>>>> +             return NULL;
>>>> +
>>>> +     types = groups->type_groups[ret];
>>>> +
>>>> +     if (type >= types->num_types)
>>>> +             return NULL;
>>>> +
>>>> +     return types->types[type];
>>>> +}
>>>> +
>>>> +static int uverbs_lock_object(struct ib_uobject *uobj,
>>>> +                           enum uverbs_idr_access access)
>>>> +{
>>>> +     if (access == UVERBS_IDR_ACCESS_READ)
>>>> +             return down_read_trylock(&uobj->usecnt) == 1 ? 0 : -
>> EBUSY;
>>>> +
>>>> +     /* lock is either WRITE or DESTROY - should be exclusive */
>>>> +     return down_write_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
>>>
>>> This function could take the lock type directly (read or write),
>> versus inferring it based on some other access type.
>>>
>>
>> We can, but since we use these enums in the attribute specifications,
>> I thought it could be more convinient.
>>
>>>> +}
>>>> +
>>>> +static struct ib_uobject *get_uobj(int id, struct ib_ucontext
>>>> *context)
>>>> +{
>>>> +     struct ib_uobject *uobj;
>>>> +
>>>> +     rcu_read_lock();
>>>> +     uobj = idr_find(&context->device->idr, id);
>>>> +     if (uobj && uobj->live) {
>>>> +             if (uobj->context != context)
>>>> +                     uobj = NULL;
>>>> +     }
>>>> +     rcu_read_unlock();
>>>> +
>>>> +     return uobj;
>>>> +}
>>>> +
>>>> +struct ib_ucontext_lock {
>>>> +     struct kref  ref;
>>>> +     /* locking the uobjects_list */
>>>> +     struct mutex lock;
>>>> +};
>>>> +
>>>> +static void init_uobjects_list_lock(struct ib_ucontext_lock *lock)
>>>> +{
>>>> +     mutex_init(&lock->lock);
>>>> +     kref_init(&lock->ref);
>>>> +}
>>>> +
>>>> +static void release_uobjects_list_lock(struct kref *ref)
>>>> +{
>>>> +     struct ib_ucontext_lock *lock = container_of(ref,
>>>> +                                                  struct
>> ib_ucontext_lock,
>>>> +                                                  ref);
>>>> +
>>>> +     kfree(lock);
>>>> +}
>>>> +
>>>> +static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
>>>> +                   struct ib_ucontext *context)
>>>> +{
>>>> +     init_rwsem(&uobj->usecnt);
>>>> +     uobj->user_handle = user_handle;
>>>> +     uobj->context     = context;
>>>> +     uobj->live        = 0;
>>>> +}
>>>> +
>>>> +static int add_uobj(struct ib_uobject *uobj)
>>>> +{
>>>> +     int ret;
>>>> +
>>>> +     idr_preload(GFP_KERNEL);
>>>> +     spin_lock(&uobj->context->device->idr_lock);
>>>> +
>>>> +     ret = idr_alloc(&uobj->context->device->idr, uobj, 0, 0,
>>>> GFP_NOWAIT);
>>>> +     if (ret >= 0)
>>>> +             uobj->id = ret;
>>>> +
>>>> +     spin_unlock(&uobj->context->device->idr_lock);
>>>> +     idr_preload_end();
>>>> +
>>>> +     return ret < 0 ? ret : 0;
>>>> +}
>>>> +
>>>> +static void remove_uobj(struct ib_uobject *uobj)
>>>> +{
>>>> +     spin_lock(&uobj->context->device->idr_lock);
>>>> +     idr_remove(&uobj->context->device->idr, uobj->id);
>>>> +     spin_unlock(&uobj->context->device->idr_lock);
>>>> +}
>>>> +
>>>> +static void put_uobj(struct ib_uobject *uobj)
>>>> +{
>>>> +     kfree_rcu(uobj, rcu);
>>>> +}
>>>> +
>>>> +static struct ib_uobject *get_uobject_from_context(struct
>> ib_ucontext
>>>> *ucontext,
>>>> +                                                const struct
>>>> uverbs_type_alloc_action *type,
>>>> +                                                u32 idr,
>>>> +                                                enum
>> uverbs_idr_access access)
>>>> +{
>>>> +     struct ib_uobject *uobj;
>>>> +     int ret;
>>>> +
>>>> +     rcu_read_lock();
>>>> +     uobj = get_uobj(idr, ucontext);
>>>> +     if (!uobj)
>>>> +             goto free;
>>>> +
>>>> +     if (uobj->type != type) {
>>>> +             uobj = NULL;
>>>> +             goto free;
>>>> +     }
>>>> +
>>>> +     ret = uverbs_lock_object(uobj, access);
>>>> +     if (ret)
>>>> +             uobj = ERR_PTR(ret);
>>>> +free:
>>>> +     rcu_read_unlock();
>>>> +     return uobj;
>>>> +
>>>> +     return NULL;
>>>> +}
>>>> +
>>>> +static int ib_uverbs_uobject_add(struct ib_uobject *uobject,
>>>> +                              const struct uverbs_type_alloc_action
>>>> *uobject_type)
>>>> +{
>>>> +     uobject->type = uobject_type;
>>>> +     return add_uobj(uobject);
>>>> +}
>>>> +
>>>> +struct ib_uobject *uverbs_get_type_from_idr(const struct
>>>> uverbs_type_alloc_action *type,
>>>> +                                         struct ib_ucontext
>> *ucontext,
>>>> +                                         enum uverbs_idr_access
>> access,
>>>> +                                         uint32_t idr)
>>>> +{
>>>> +     struct ib_uobject *uobj;
>>>> +     int ret;
>>>> +
>>>> +     if (access == UVERBS_IDR_ACCESS_NEW) {
>>>> +             uobj = kmalloc(type->obj_size, GFP_KERNEL);
>>>> +             if (!uobj)
>>>> +                     return ERR_PTR(-ENOMEM);
>>>> +
>>>> +             init_uobj(uobj, 0, ucontext);
>>>> +
>>>> +             /* lock idr */
>>>
>>> Command to lock idr, but no lock is obtained.
>>>
>>
>> ib_uverbs_uobject_add calls add_uobj which locks the IDR.
>>
>>>> +             ret = ib_uverbs_uobject_add(uobj, type);
>>>> +             if (ret) {
>>>> +                     kfree(uobj);
>>>> +                     return ERR_PTR(ret);
>>>> +             }
>>>> +
>>>> +     } else {
>>>> +             uobj = get_uobject_from_context(ucontext, type, idr,
>>>> +                                             access);
>>>> +
>>>> +             if (!uobj)
>>>> +                     return ERR_PTR(-ENOENT);
>>>> +     }
>>>> +
>>>> +     return uobj;
>>>> +}
>>>> +
>>>> +struct ib_uobject *uverbs_get_type_from_fd(const struct
>>>> uverbs_type_alloc_action *type,
>>>> +                                        struct ib_ucontext
>> *ucontext,
>>>> +                                        enum uverbs_idr_access
>> access,
>>>> +                                        int fd)
>>>> +{
>>>> +     if (access == UVERBS_IDR_ACCESS_NEW) {
>>>> +             int _fd;
>>>> +             struct ib_uobject *uobj = NULL;
>>>> +             struct file *filp;
>>>> +
>>>> +             _fd = get_unused_fd_flags(O_CLOEXEC);
>>>> +             if (_fd < 0 || WARN_ON(type->obj_size < sizeof(struct
>>>> ib_uobject)))
>>>> +                     return ERR_PTR(_fd);
>>>> +
>>>> +             uobj = kmalloc(type->obj_size, GFP_KERNEL);
>>>> +             init_uobj(uobj, 0, ucontext);
>>>> +
>>>> +             if (!uobj)
>>>> +                     return ERR_PTR(-ENOMEM);
>>>> +
>>>> +             filp = anon_inode_getfile(type->fd.name, type-
>>> fd.fops,
>>>> +                                       uobj + 1, type->fd.flags);
>>>> +             if (IS_ERR(filp)) {
>>>> +                     put_unused_fd(_fd);
>>>> +                     kfree(uobj);
>>>> +                     return (void *)filp;
>>>> +             }
>>>> +
>>>> +             uobj->type = type;
>>>> +             uobj->id = _fd;
>>>> +             uobj->object = filp;
>>>> +
>>>> +             return uobj;
>>>> +     } else if (access == UVERBS_IDR_ACCESS_READ) {
>>>> +             struct file *f = fget(fd);
>>>> +             struct ib_uobject *uobject;
>>>> +
>>>> +             if (!f)
>>>> +                     return ERR_PTR(-EBADF);
>>>> +
>>>> +             uobject = f->private_data - sizeof(struct ib_uobject);
>>>> +             if (f->f_op != type->fd.fops ||
>>>> +                 !uobject->live) {
>>>> +                     fput(f);
>>>> +                     return ERR_PTR(-EBADF);
>>>> +             }
>>>> +
>>>> +             /*
>>>> +              * No need to protect it with a ref count, as fget
>>>> increases
>>>> +              * f_count.
>>>> +              */
>>>> +             return uobject;
>>>> +     } else {
>>>> +             return ERR_PTR(-EOPNOTSUPP);
>>>> +     }
>>>> +}
>>>> +
>>>> +static void ib_uverbs_uobject_enable(struct ib_uobject *uobject)
>>>> +{
>>>> +     mutex_lock(&uobject->context->uobjects_lock->lock);
>>>> +     list_add(&uobject->list, &uobject->context->uobjects);
>>>> +     mutex_unlock(&uobject->context->uobjects_lock->lock);
>>>
>>> Why not just insert the object into the list on creation?
>>>
>>>> +     uobject->live = 1;
>>>
>>> See my comments above on removing the live field.
>>>
>>
>> Seems that the list could suffice, but I'll look into that.
>>
>>>> +}
>>>> +
>>>> +static void ib_uverbs_uobject_remove(struct ib_uobject *uobject,
>> bool
>>>> lock)
>>>> +{
>>>> +     /*
>>>> +      * Calling remove requires exclusive access, so it's not
>> possible
>>>> +      * another thread will use our object.
>>>> +      */
>>>> +     uobject->live = 0;
>>>> +     uobject->type->free_fn(uobject->type, uobject);
>>>> +     if (lock)
>>>> +             mutex_lock(&uobject->context->uobjects_lock->lock);
>>>> +     list_del(&uobject->list);
>>>> +     if (lock)
>>>> +             mutex_unlock(&uobject->context->uobjects_lock->lock);
>>>> +     remove_uobj(uobject);
>>>> +     put_uobj(uobject);
>>>> +}
>>>> +
>>>> +static void uverbs_unlock_idr(struct ib_uobject *uobj,
>>>> +                           enum uverbs_idr_access access,
>>>> +                           bool success)
>>>> +{
>>>> +     switch (access) {
>>>> +     case UVERBS_IDR_ACCESS_READ:
>>>> +             up_read(&uobj->usecnt);
>>>> +             break;
>>>> +     case UVERBS_IDR_ACCESS_NEW:
>>>> +             if (success) {
>>>> +                     ib_uverbs_uobject_enable(uobj);
>>>> +             } else {
>>>> +                     remove_uobj(uobj);
>>>> +                     put_uobj(uobj);
>>>> +             }
>>>> +             break;
>>>> +     case UVERBS_IDR_ACCESS_WRITE:
>>>> +             up_write(&uobj->usecnt);
>>>> +             break;
>>>> +     case UVERBS_IDR_ACCESS_DESTROY:
>>>> +             if (success)
>>>> +                     ib_uverbs_uobject_remove(uobj, true);
>>>> +             else
>>>> +                     up_write(&uobj->usecnt);
>>>> +             break;
>>>> +     }
>>>> +}
>>>> +
>>>> +static void uverbs_unlock_fd(struct ib_uobject *uobj,
>>>> +                          enum uverbs_idr_access access,
>>>> +                          bool success)
>>>> +{
>>>> +     struct file *filp = uobj->object;
>>>> +
>>>> +     if (access == UVERBS_IDR_ACCESS_NEW) {
>>>> +             if (success) {
>>>> +                     kref_get(&uobj->context->ufile->ref);
>>>> +                     uobj->uobjects_lock = uobj->context-
>>> uobjects_lock;
>>>> +                     kref_get(&uobj->uobjects_lock->ref);
>>>> +                     ib_uverbs_uobject_enable(uobj);
>>>> +                     fd_install(uobj->id, uobj->object);
>>>
>>> I don't get this.  The function is unlocking something, but there are
>> calls to get krefs?
>>>
>>
>> Before invoking the user's callback, we're first locking all objects
>> and afterwards we're unlocking them. When we need to create a new
>> object, the lock becomes object creation and the unlock could become
>> (assuming the user's callback succeeded) enabling this new object.
>> When you add a new object (or fd in this case), we take a reference
>> count to both the uverbs_file and the locking context.
>>
>>>> +             } else {
>>>> +                     fput(uobj->object);
>>>> +                     put_unused_fd(uobj->id);
>>>> +                     kfree(uobj);
>>>> +             }
>>>> +     } else {
>>>> +             fput(filp);
>>>> +     }
>>>> +}
>>>> +
>>>> +void uverbs_unlock_object(struct ib_uobject *uobj,
>>>> +                       enum uverbs_idr_access access,
>>>> +                       bool success)
>>>> +{
>>>> +     if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
>>>> +             uverbs_unlock_idr(uobj, access, success);
>>>> +     else if (uobj->type->type == UVERBS_ATTR_TYPE_FD)
>>>> +             uverbs_unlock_fd(uobj, access, success);
>>>> +     else
>>>> +             WARN_ON(true);
>>>> +}
>>>> +
>>>> +static void ib_uverbs_remove_fd(struct ib_uobject *uobject)
>>>> +{
>>>> +     /*
>>>> +      * user should release the uobject in the release
>>>> +      * callback.
>>>> +      */
>>>> +     if (uobject->live) {
>>>> +             uobject->live = 0;
>>>> +             list_del(&uobject->list);
>>>> +             uobject->type->free_fn(uobject->type, uobject);
>>>> +             kref_put(&uobject->context->ufile->ref,
>>>> ib_uverbs_release_file);
>>>> +             uobject->context = NULL;
>>>> +     }
>>>> +}
>>>> +
>>>> +void ib_uverbs_close_fd(struct file *f)
>>>> +{
>>>> +     struct ib_uobject *uobject = f->private_data - sizeof(struct
>>>> ib_uobject);
>>>> +
>>>> +     mutex_lock(&uobject->uobjects_lock->lock);
>>>> +     if (uobject->live) {
>>>> +             uobject->live = 0;
>>>> +             list_del(&uobject->list);
>>>> +             kref_put(&uobject->context->ufile->ref,
>>>> ib_uverbs_release_file);
>>>> +             uobject->context = NULL;
>>>> +     }
>>>> +     mutex_unlock(&uobject->uobjects_lock->lock);
>>>> +     kref_put(&uobject->uobjects_lock->ref,
>>>> release_uobjects_list_lock);
>>>> +}
>>>> +
>>>> +void ib_uverbs_cleanup_fd(void *private_data)
>>>> +{
>>>> +     struct ib_uboject *uobject = private_data - sizeof(struct
>>>> ib_uobject);
>>>> +
>>>> +     kfree(uobject);
>>>> +}
>>>> +
>>>> +void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
>>>> +                        size_t num,
>>>> +                        const struct uverbs_action_spec *spec,
>>>> +                        bool success)
>>>> +{
>>>> +     unsigned int i;
>>>> +
>>>> +     for (i = 0; i < num; i++) {
>>>> +             struct uverbs_attr_array *attr_spec_array =
>> &attr_array[i];
>>>> +             const struct uverbs_attr_group_spec *group_spec =
>>>> +                     spec->attr_groups[i];
>>>> +             unsigned int j;
>>>> +
>>>> +             for (j = 0; j < attr_spec_array->num_attrs; j++) {
>>>> +                     struct uverbs_attr *attr = &attr_spec_array-
>>>>> attrs[j];
>>>> +                     struct uverbs_attr_spec *spec = &group_spec-
>>>>> attrs[j];
>>>> +
>>>> +                     if (!attr->valid)
>>>> +                             continue;
>>>> +
>>>> +                     if (spec->type == UVERBS_ATTR_TYPE_IDR ||
>>>> +                         spec->type == UVERBS_ATTR_TYPE_FD)
>>>> +                             /*
>>>> +                              * refcounts should be handled at the
>> object
>>>> +                              * level and not at the uobject level.
>>>> +                              */
>>>> +                             uverbs_unlock_object(attr-
>>> obj_attr.uobject,
>>>> +                                                  spec->obj.access,
>> success);
>>>> +             }
>>>> +     }
>>>> +}
>>>> +
>>>> +static unsigned int get_type_orders(const struct uverbs_types_group
>>>> *types_group)
>>>> +{
>>>> +     unsigned int i;
>>>> +     unsigned int max = 0;
>>>> +
>>>> +     for (i = 0; i < types_group->num_groups; i++) {
>>>> +             unsigned int j;
>>>> +             const struct uverbs_types *types = types_group-
>>>>> type_groups[i];
>>>> +
>>>> +             for (j = 0; j < types->num_types; j++) {
>>>> +                     if (!types->types[j] || !types->types[j]-
>>> alloc)
>>>> +                             continue;
>>>> +                     if (types->types[j]->alloc->order > max)
>>>> +                             max = types->types[j]->alloc->order;
>>>> +             }
>>>> +     }
>>>> +
>>>> +     return max;
>>>> +}
>>>> +
>>>> +void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext
>>>> *ucontext,
>>>> +                                          const struct
>> uverbs_types_group
>>>> *types_group)
>>>> +{
>>>> +     unsigned int num_orders = get_type_orders(types_group);
>>>> +     unsigned int i;
>>>> +
>>>> +     for (i = 0; i <= num_orders; i++) {
>>>> +             struct ib_uobject *obj, *next_obj;
>>>> +
>>>> +             /*
>>>> +              * No need to take lock here, as cleanup should be
>> called
>>>> +              * after all commands finished executing. Newly
>> executed
>>>> +              * commands should fail.
>>>> +              */
>>>> +             mutex_lock(&ucontext->uobjects_lock->lock);
>>>
>>> It's really confusing to see a comment about 'no need to take lock'
>> immediately followed by a call to lock.
>>>
>>
>> Yeah :) That was before adding the fd. I'll delete the comment.
>>
>>>> +             list_for_each_entry_safe(obj, next_obj, &ucontext-
>>>>> uobjects,
>>>> +                                      list)
>>>> +                     if (obj->type->order == i) {
>>>> +                             if (obj->type->type ==
>> UVERBS_ATTR_TYPE_IDR)
>>>> +                                     ib_uverbs_uobject_remove(obj,
>> false);
>>>> +                             else
>>>> +                                     ib_uverbs_remove_fd(obj);
>>>> +                     }
>>>> +             mutex_unlock(&ucontext->uobjects_lock->lock);
>>>> +     }
>>>> +     kref_put(&ucontext->uobjects_lock->ref,
>>>> release_uobjects_list_lock);
>>>> +}
>>>> +
>>>> +int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext
>>>> *ucontext)
>>>
>>> Please work on the function names.  This is horrendously long and
>> still doesn't help describe what it does.
>>>
>>
>> This just initialized the types part of the ucontext. Any suggestions?
>>
>>>> +{
>>>> +     ucontext->uobjects_lock = kmalloc(sizeof(*ucontext-
>>>>> uobjects_lock),
>>>> +                                       GFP_KERNEL);
>>>> +     if (!ucontext->uobjects_lock)
>>>> +             return -ENOMEM;
>>>> +
>>>> +     init_uobjects_list_lock(ucontext->uobjects_lock);
>>>> +     INIT_LIST_HEAD(&ucontext->uobjects);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext
>>>> *ucontext)
>>>> +{
>>>> +     kfree(ucontext->uobjects_lock);
>>>> +}
>>>
>>> No need to wrap a call to 'free'.
>>>
>>
>> In order to abstract away the ucontext type data structure.
>>
>>>> +
>>>> diff --git a/drivers/infiniband/core/rdma_core.h
>>>> b/drivers/infiniband/core/rdma_core.h
>>>> new file mode 100644
>>>> index 0000000..8990115
>>>> --- /dev/null
>>>> +++ b/drivers/infiniband/core/rdma_core.h
>>>> @@ -0,0 +1,75 @@
>>>> +/*
>>>> + * Copyright (c) 2005 Topspin Communications.  All rights reserved.
>>>> + * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
>>>> + * Copyright (c) 2005-2016 Mellanox Technologies. All rights
>> reserved.
>>>> + * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
>>>> + * Copyright (c) 2005 PathScale, Inc. All rights reserved.
>>>> + *
>>>> + * This software is available to you under a choice of one of two
>>>> + * licenses.  You may choose to be licensed under the terms of the
>> GNU
>>>> + * General Public License (GPL) Version 2, available from the file
>>>> + * COPYING in the main directory of this source tree, or the
>>>> + * OpenIB.org BSD license below:
>>>> + *
>>>> + *     Redistribution and use in source and binary forms, with or
>>>> + *     without modification, are permitted provided that the
>> following
>>>> + *     conditions are met:
>>>> + *
>>>> + *      - Redistributions of source code must retain the above
>>>> + *        copyright notice, this list of conditions and the
>> following
>>>> + *        disclaimer.
>>>> + *
>>>> + *      - Redistributions in binary form must reproduce the above
>>>> + *        copyright notice, this list of conditions and the
>> following
>>>> + *        disclaimer in the documentation and/or other materials
>>>> + *        provided with the distribution.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>> OF
>>>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>>>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
>> HOLDERS
>>>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
>> AN
>>>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
>> IN
>>>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>>>> + * SOFTWARE.
>>>> + */
>>>> +
>>>> +#ifndef UOBJECT_H
>>>> +#define UOBJECT_H
>>>> +
>>>> +#include <linux/idr.h>
>>>> +#include <rdma/uverbs_ioctl.h>
>>>> +#include <rdma/ib_verbs.h>
>>>> +#include <linux/mutex.h>
>>>> +
>>>> +const struct uverbs_type *uverbs_get_type(const struct ib_device
>>>> *ibdev,
>>>> +                                       uint16_t type);
>>>> +struct ib_uobject *uverbs_get_type_from_idr(const struct
>>>> uverbs_type_alloc_action *type,
>>>> +                                         struct ib_ucontext
>> *ucontext,
>>>> +                                         enum uverbs_idr_access
>> access,
>>>> +                                         uint32_t idr);
>>>> +struct ib_uobject *uverbs_get_type_from_fd(const struct
>>>> uverbs_type_alloc_action *type,
>>>> +                                        struct ib_ucontext
>> *ucontext,
>>>> +                                        enum uverbs_idr_access
>> access,
>>>> +                                        int fd);
>>>> +void uverbs_unlock_object(struct ib_uobject *uobj,
>>>> +                       enum uverbs_idr_access access,
>>>> +                       bool success);
>>>> +void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
>>>> +                        size_t num,
>>>> +                        const struct uverbs_action_spec *spec,
>>>> +                        bool success);
>>>> +
>>>> +void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext
>>>> *ucontext,
>>>> +                                          const struct
>> uverbs_types_group
>>>> *types_group);
>>>> +int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext
>>>> *ucontext);
>>>> +void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext
>>>> *ucontext);
>>>> +void ib_uverbs_close_fd(struct file *f);
>>>> +void ib_uverbs_cleanup_fd(void *private_data);
>>>> +
>>>> +static inline void *uverbs_fd_to_priv(struct ib_uobject *uobj)
>>>> +{
>>>> +     return uobj + 1;
>>>> +}
>>>
>>> This seems like a rather useless function.
>>>
>>
>> Why? The user sholdn't know or care how we put our structs together.
>>
>>>> +
>>>> +#endif /* UIDR_H */
>>>> diff --git a/drivers/infiniband/core/uverbs.h
>>>> b/drivers/infiniband/core/uverbs.h
>>>> index 8074705..ae7d4b8 100644
>>>> --- a/drivers/infiniband/core/uverbs.h
>>>> +++ b/drivers/infiniband/core/uverbs.h
>>>> @@ -180,6 +180,7 @@ void idr_remove_uobj(struct ib_uobject *uobj);
>>>>  struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file
>>>> *uverbs_file,
>>>>                                       struct ib_device *ib_dev,
>>>>                                       int is_async);
>>>> +void ib_uverbs_release_file(struct kref *ref);
>>>>  void ib_uverbs_free_async_event_file(struct ib_uverbs_file
>>>> *uverbs_file);
>>>>  struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
>>>>
>>>> diff --git a/drivers/infiniband/core/uverbs_main.c
>>>> b/drivers/infiniband/core/uverbs_main.c
>>>> index f783723..e63357a 100644
>>>> --- a/drivers/infiniband/core/uverbs_main.c
>>>> +++ b/drivers/infiniband/core/uverbs_main.c
>>>> @@ -341,7 +341,7 @@ static void ib_uverbs_comp_dev(struct
>>>> ib_uverbs_device *dev)
>>>>       complete(&dev->comp);
>>>>  }
>>>>
>>>> -static void ib_uverbs_release_file(struct kref *ref)
>>>> +void ib_uverbs_release_file(struct kref *ref)
>>>>  {
>>>>       struct ib_uverbs_file *file =
>>>>               container_of(ref, struct ib_uverbs_file, ref);
>>>> diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
>>>> index b5d2075..7240615 100644
>>>> --- a/include/rdma/ib_verbs.h
>>>> +++ b/include/rdma/ib_verbs.h
>>>> @@ -1329,8 +1329,11 @@ struct ib_fmr_attr {
>>>>
>>>>  struct ib_umem;
>>>>
>>>> +struct ib_ucontext_lock;
>>>> +
>>>>  struct ib_ucontext {
>>>>       struct ib_device       *device;
>>>> +     struct ib_uverbs_file  *ufile;
>>>>       struct list_head        pd_list;
>>>>       struct list_head        mr_list;
>>>>       struct list_head        mw_list;
>>>> @@ -1344,6 +1347,10 @@ struct ib_ucontext {
>>>>       struct list_head        rwq_ind_tbl_list;
>>>>       int                     closing;
>>>>
>>>> +     /* lock for uobjects list */
>>>> +     struct ib_ucontext_lock *uobjects_lock;
>>>> +     struct list_head        uobjects;
>>>> +
>>>>       struct pid             *tgid;
>>>>  #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
>>>>       struct rb_root      umem_tree;
>>>> @@ -1363,16 +1370,28 @@ struct ib_ucontext {
>>>>  #endif
>>>>  };
>>>>
>>>> +struct uverbs_object_list;
>>>> +
>>>> +#define OLD_ABI_COMPAT
>>>> +
>>>>  struct ib_uobject {
>>>>       u64                     user_handle;    /* handle given to us
>> by userspace
>>>> */
>>>>       struct ib_ucontext     *context;        /* associated user
>> context
>>>> */
>>>>       void                   *object;         /* containing object
>> */
>>>>       struct list_head        list;           /* link to context's
>> list */
>>>> -     int                     id;             /* index into kernel
>> idr */
>>>> -     struct kref             ref;
>>>> -     struct rw_semaphore     mutex;          /* protects .live */
>>>> +     int                     id;             /* index into kernel
>> idr/fd */
>>>> +#ifdef OLD_ABI_COMPAT
>>>> +     struct kref             ref;
>>>> +#endif
>>>> +     struct rw_semaphore     usecnt;         /* protects exclusive
>>>> access */
>>>> +#ifdef OLD_ABI_COMPAT
>>>> +     struct rw_semaphore     mutex;          /* protects .live */
>>>> +#endif
>>>>       struct rcu_head         rcu;            /* kfree_rcu()
>> overhead */
>>>>       int                     live;
>>>> +
>>>> +     const struct uverbs_type_alloc_action *type;
>>>> +     struct ib_ucontext_lock *uobjects_lock;
>>>>  };
>>>>
>>>>  struct ib_udata {
>>>> @@ -2101,6 +2120,9 @@ struct ib_device {
>>>>        */
>>>>       int (*get_port_immutable)(struct ib_device *, u8, struct
>>>> ib_port_immutable *);
>>>>       void (*get_dev_fw_str)(struct ib_device *, char *str, size_t
>>>> str_len);
>>>> +     struct list_head type_list;
>>>> +
>>>> +     const struct uverbs_types_group *types_group;
>>>>  };
>>>>
>>>>  struct ib_client {
>>>> diff --git a/include/rdma/uverbs_ioctl.h
>> b/include/rdma/uverbs_ioctl.h
>>>> new file mode 100644
>>>> index 0000000..2f50045
>>>> --- /dev/null
>>>> +++ b/include/rdma/uverbs_ioctl.h
>>>> @@ -0,0 +1,195 @@
>>>> +/*
>>>> + * Copyright (c) 2016, Mellanox Technologies inc.  All rights
>>>> reserved.
>>>> + *
>>>> + * This software is available to you under a choice of one of two
>>>> + * licenses.  You may choose to be licensed under the terms of the
>> GNU
>>>> + * General Public License (GPL) Version 2, available from the file
>>>> + * COPYING in the main directory of this source tree, or the
>>>> + * OpenIB.org BSD license below:
>>>> + *
>>>> + *     Redistribution and use in source and binary forms, with or
>>>> + *     without modification, are permitted provided that the
>> following
>>>> + *     conditions are met:
>>>> + *
>>>> + *      - Redistributions of source code must retain the above
>>>> + *        copyright notice, this list of conditions and the
>> following
>>>> + *        disclaimer.
>>>> + *
>>>> + *      - Redistributions in binary form must reproduce the above
>>>> + *        copyright notice, this list of conditions and the
>> following
>>>> + *        disclaimer in the documentation and/or other materials
>>>> + *        provided with the distribution.
>>>> + *
>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>> OF
>>>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>>>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
>> HOLDERS
>>>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
>> AN
>>>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
>> IN
>>>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>>>> + * SOFTWARE.
>>>> + */
>>>> +
>>>> +#ifndef _UVERBS_IOCTL_
>>>> +#define _UVERBS_IOCTL_
>>>> +
>>>> +#include <linux/kernel.h>
>>>> +
>>>> +struct uverbs_object_type;
>>>> +struct ib_ucontext;
>>>> +struct ib_uobject;
>>>> +struct ib_device;
>>>> +struct uverbs_uobject_type;
>>>> +
>>>> +/*
>>>> + * =======================================
>>>> + *   Verbs action specifications
>>>> + * =======================================
>>>> + */
>>>
>>> I intentionally used urdma (though condensed to 3 letters that I
>> don't recall atm), rather than uverbs.  This will need to work with
>> non-verbs devices and interfaces -- again, consider how this fits with
>> the rdma cm.  Verbs has a very specific meaning, which gets lost if we
>> start referring to everything as 'verbs'.  It's bad enough that we're
>> stuck with 'drivers/infiniband' and 'rdma', such that 'infiniband' also
>> means ethernet and rdma means nothing.
>>>
>>
>> IMHO - let's agree on the concept of this infrastructure. One we
>> decide its scope, we could generalize it (i.e - ioctl_provider and
>> ioctl_context) and implement it to rdma-cm as well.
>>
>>>> +
>>>> +enum uverbs_attr_type {
>>>> +     UVERBS_ATTR_TYPE_PTR_IN,
>>>> +     UVERBS_ATTR_TYPE_PTR_OUT,
>>>> +     UVERBS_ATTR_TYPE_IDR,
>>>> +     UVERBS_ATTR_TYPE_FD,
>>>> +};
>>>> +
>>>> +enum uverbs_idr_access {
>>>> +     UVERBS_IDR_ACCESS_READ,
>>>> +     UVERBS_IDR_ACCESS_WRITE,
>>>> +     UVERBS_IDR_ACCESS_NEW,
>>>> +     UVERBS_IDR_ACCESS_DESTROY
>>>> +};
>>>> +
>>>> +struct uverbs_attr_spec {
>>>> +     u16                             len;
>>>> +     enum uverbs_attr_type           type;
>>>> +     struct {
>>>> +             u16                     obj_type;
>>>> +             u8                      access;
>>>
>>> Is access intended to be an enum uverbs_idr_access value?
>>>
>>
>> Yeah, worth using this enum. Thanks.
>>
>>>> +     } obj;
>>>
>>> I would remove (flatten) the substructure and re-order the fields for
>> better alignment.
>>>
>>
>> I noticed there are several places which aren't aliged. It's in my todo
>> list.
>>
>>>> +};
>>>> +
>>>> +struct uverbs_attr_group_spec {
>>>> +     struct uverbs_attr_spec         *attrs;
>>>> +     size_t                          num_attrs;
>>>> +};
>>>> +
>>>> +struct uverbs_action_spec {
>>>> +     const struct uverbs_attr_group_spec             **attr_groups;
>>>> +     /* if > 0 -> validator, otherwise, error */
>>>
>>> ? not sure what this comment means
>>>
>>>> +     int (*dist)(__u16 *attr_id, void *priv);
>>>
>>> What does 'dist' stand for?
>>>
>>
>> dist = distribution function.
>> It maps the attributes you got from the user-space to your groups. You
>> could think of each group as a namespace - where its attributes (or
>> types/actions) starts from zero in the sake of compactness.
>> So, for example, it gets an attribute 0x8010 and maps to to "group 1"
>> (provider) and attribute 0x10.
>>
>>>> +     void                                            *priv;
>>>> +     size_t                                          num_groups;
>>>> +};
>>>> +
>>>> +struct uverbs_attr_array;
>>>> +struct ib_uverbs_file;
>>>> +
>>>> +struct uverbs_action {
>>>> +     struct uverbs_action_spec spec;
>>>> +     void *priv;
>>>> +     int (*handler)(struct ib_device *ib_dev, struct ib_uverbs_file
>>>> *ufile,
>>>> +                    struct uverbs_attr_array *ctx, size_t num, void
>>>> *priv);
>>>> +};
>>>> +
>>>> +struct uverbs_type_alloc_action;
>>>> +typedef void (*free_type)(const struct uverbs_type_alloc_action
>>>> *uobject_type,
>>>> +                       struct ib_uobject *uobject);
>>>> +
>>>> +struct uverbs_type_alloc_action {
>>>> +     enum uverbs_attr_type           type;
>>>> +     int                             order;
>>>
>>> I think this is being used as destroy order, in which case I would
>> rename it to clarify the intent.  Though I'd prefer we come up with a
>> more efficient destruction mechanism than the repeated nested looping.
>>>
>>
>> In one of the earlier revisions I used a sorted list, which was
>> efficient. I recall that Jason didn't like its complexity and
>> re-thinking about that - he's right. Most of your types are "order
>> number" 0 anyway. So you'll probably iterate very few objects in the
>> next round (in verbs, everything but MRs and PDs).
>>
>>>> +     size_t                          obj_size;
>>>
>>> This can be alloc_fn
>>>
>>>> +     free_type                       free_fn;
>>>> +     struct {
>>>> +             const struct file_operations    *fops;
>>>> +             const char                      *name;
>>>> +             int                             flags;
>>>> +     } fd;
>>>> +};
>>>> +
>>>> +struct uverbs_type_actions_group {
>>>> +     size_t                                  num_actions;
>>>> +     const struct uverbs_action              **actions;
>>>> +};
>>>> +
>>>> +struct uverbs_type {
>>>> +     size_t                                  num_groups;
>>>> +     const struct uverbs_type_actions_group  **action_groups;
>>>> +     const struct uverbs_type_alloc_action   *alloc;
>>>> +     int (*dist)(__u16 *action_id, void *priv);
>>>> +     void                                    *priv;
>>>> +};
>>>> +
>>>> +struct uverbs_types {
>>>> +     size_t                                  num_types;
>>>> +     const struct uverbs_type                **types;
>>>> +};
>>>> +
>>>> +struct uverbs_types_group {
>>>> +     const struct uverbs_types               **type_groups;
>>>> +     size_t                                  num_groups;
>>>> +     int (*dist)(__u16 *type_id, void *priv);
>>>> +     void                                    *priv;
>>>> +};
>>>> +
>>>> +/* =================================================
>>>> + *              Parsing infrastructure
>>>> + * =================================================
>>>> + */
>>>> +
>>>> +struct uverbs_ptr_attr {
>>>> +     void    * __user ptr;
>>>> +     __u16           len;
>>>> +};
>>>> +
>>>> +struct uverbs_fd_attr {
>>>> +     int             fd;
>>>> +};
>>>> +
>>>> +struct uverbs_uobj_attr {
>>>> +     /*  idr handle */
>>>> +     __u32   idr;
>>>> +};
>>>> +
>>>> +struct uverbs_obj_attr {
>>>> +     /* pointer to the kernel descriptor -> type, access, etc */
>>>> +     const struct uverbs_attr_spec *val;
>>>> +     struct ib_uverbs_attr __user    *uattr;
>>>> +     const struct uverbs_type_alloc_action   *type;
>>>> +     struct ib_uobject               *uobject;
>>>> +     union {
>>>> +             struct uverbs_fd_attr           fd;
>>>> +             struct uverbs_uobj_attr         uobj;
>>>> +     };
>>>> +};
>>>> +
>>>> +struct uverbs_attr {
>>>> +     bool valid; > >> +     union {
>>>> +             struct uverbs_ptr_attr  cmd_attr;
>>>> +             struct uverbs_obj_attr  obj_attr;
>>>> +     };
>>>> +};
>>>
>>> It's odd to have a union that's part of a structure without some
>> field to indicate which union field is accessible.
>>>
>>
>> You index this array but the attribute id from the user's callback
>> funciton. The user should know what's the type of the attribute, as
>> [s]he declared the specification.
>>
>>>> +
>>>> +/* output of one validator */
>>>> +struct uverbs_attr_array {
>>>> +     size_t num_attrs;
>>>> +     /* arrays of attrubytes, index is the id i.e SEND_CQ */
>>>> +     struct uverbs_attr *attrs;
>>>> +};
>>>> +
>>>> +/* =================================================
>>>> + *              Types infrastructure
>>>> + * =================================================
>>>> + */
>>>> +
>>>> +int ib_uverbs_uobject_type_add(struct list_head      *head,
>>>> +                            void (*free)(struct uverbs_uobject_type
>> *type,
>>>> +                                         struct ib_uobject
>> *uobject,
>>>> +                                         struct ib_ucontext
>> *ucontext),
>>>> +                            uint16_t obj_type);
>>>> +void ib_uverbs_uobject_types_remove(struct ib_device *ib_dev);
>>>> +
>>>> +#endif
>>>> --
>>>> 2.7.4
>
> Matan, please re-look at the architecture that I proposed:
>
> https://patchwork.kernel.org/patch/9178991/
>
> including the terminology (and consider using common OOP terms).  The *core* of the ioctl framework is to simply invoke a function dispatch table.  IMO, that's where we should start.  Anything beyond that is extra that we should have a strong reason for including.  (Yes, I think we need more.)  Starting simple and adding necessary functionality should let us get something upstream quicker and re-use more of the existing code.

Actually, I've looked at your proposal. Some of the ideas are blend 
between your proposal and my original proposal.
One of our goals is to get rid of the commonalities between handlers and 
push the validation and locking to a common code which could validated 
once to be correct. It tends to be a lot easier (and correct) than to 
re-examine every function call.

>
> If we're going to re-create netlink as part of the rdma ioctl interface, then why don't we just use netlink directly?
>

We had a netlink based proposal first, but:
(a) We want one call dispatching (as opposed to send-receive).
(b) We don't want to copy the driver's data from the user-space to the 
libibverbs buffer.
(c) We don't need the complexity of nesting.
(d) Bare netlink is considered unreliable.
(e) We need semantics of objects.
(f) By using pointers, we could eliminate some copies.

Thanks for looking at this patch.

Matan
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index edaae9f..1819623 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -28,4 +28,5 @@  ib_umad-y :=			user_mad.o
 
 ib_ucm-y :=			ucm.o
 
-ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_marshall.o
+ib_uverbs-y :=			uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
+				rdma_core.o
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index c3b68f5..43994b1 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -243,6 +243,7 @@  struct ib_device *ib_alloc_device(size_t size)
 	spin_lock_init(&device->client_data_lock);
 	INIT_LIST_HEAD(&device->client_data_list);
 	INIT_LIST_HEAD(&device->port_list);
+	INIT_LIST_HEAD(&device->type_list);
 
 	return device;
 }
diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
new file mode 100644
index 0000000..337abc2
--- /dev/null
+++ b/drivers/infiniband/core/rdma_core.c
@@ -0,0 +1,489 @@ 
+/*
+ * Copyright (c) 2016, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/file.h>
+#include <linux/anon_inodes.h>
+#include <rdma/ib_verbs.h>
+#include "uverbs.h"
+#include "rdma_core.h"
+#include <rdma/uverbs_ioctl.h>
+
+const struct uverbs_type *uverbs_get_type(const struct ib_device *ibdev,
+					  uint16_t type)
+{
+	const struct uverbs_types_group *groups = ibdev->types_group;
+	const struct uverbs_types *types;
+	int ret = groups->dist(&type, groups->priv);
+
+	if (ret >= groups->num_groups)
+		return NULL;
+
+	types = groups->type_groups[ret];
+
+	if (type >= types->num_types)
+		return NULL;
+
+	return types->types[type];
+}
+
+static int uverbs_lock_object(struct ib_uobject *uobj,
+			      enum uverbs_idr_access access)
+{
+	if (access == UVERBS_IDR_ACCESS_READ)
+		return down_read_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
+
+	/* lock is either WRITE or DESTROY - should be exclusive */
+	return down_write_trylock(&uobj->usecnt) == 1 ? 0 : -EBUSY;
+}
+
+static struct ib_uobject *get_uobj(int id, struct ib_ucontext *context)
+{
+	struct ib_uobject *uobj;
+
+	rcu_read_lock();
+	uobj = idr_find(&context->device->idr, id);
+	if (uobj && uobj->live) {
+		if (uobj->context != context)
+			uobj = NULL;
+	}
+	rcu_read_unlock();
+
+	return uobj;
+}
+
+struct ib_ucontext_lock {
+	struct kref  ref;
+	/* locking the uobjects_list */
+	struct mutex lock;
+};
+
+static void init_uobjects_list_lock(struct ib_ucontext_lock *lock)
+{
+	mutex_init(&lock->lock);
+	kref_init(&lock->ref);
+}
+
+static void release_uobjects_list_lock(struct kref *ref)
+{
+	struct ib_ucontext_lock *lock = container_of(ref,
+						     struct ib_ucontext_lock,
+						     ref);
+
+	kfree(lock);
+}
+
+static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
+		      struct ib_ucontext *context)
+{
+	init_rwsem(&uobj->usecnt);
+	uobj->user_handle = user_handle;
+	uobj->context     = context;
+	uobj->live        = 0;
+}
+
+static int add_uobj(struct ib_uobject *uobj)
+{
+	int ret;
+
+	idr_preload(GFP_KERNEL);
+	spin_lock(&uobj->context->device->idr_lock);
+
+	ret = idr_alloc(&uobj->context->device->idr, uobj, 0, 0, GFP_NOWAIT);
+	if (ret >= 0)
+		uobj->id = ret;
+
+	spin_unlock(&uobj->context->device->idr_lock);
+	idr_preload_end();
+
+	return ret < 0 ? ret : 0;
+}
+
+static void remove_uobj(struct ib_uobject *uobj)
+{
+	spin_lock(&uobj->context->device->idr_lock);
+	idr_remove(&uobj->context->device->idr, uobj->id);
+	spin_unlock(&uobj->context->device->idr_lock);
+}
+
+static void put_uobj(struct ib_uobject *uobj)
+{
+	kfree_rcu(uobj, rcu);
+}
+
+static struct ib_uobject *get_uobject_from_context(struct ib_ucontext *ucontext,
+						   const struct uverbs_type_alloc_action *type,
+						   u32 idr,
+						   enum uverbs_idr_access access)
+{
+	struct ib_uobject *uobj;
+	int ret;
+
+	rcu_read_lock();
+	uobj = get_uobj(idr, ucontext);
+	if (!uobj)
+		goto free;
+
+	if (uobj->type != type) {
+		uobj = NULL;
+		goto free;
+	}
+
+	ret = uverbs_lock_object(uobj, access);
+	if (ret)
+		uobj = ERR_PTR(ret);
+free:
+	rcu_read_unlock();
+	return uobj;
+
+	return NULL;
+}
+
+static int ib_uverbs_uobject_add(struct ib_uobject *uobject,
+				 const struct uverbs_type_alloc_action *uobject_type)
+{
+	uobject->type = uobject_type;
+	return add_uobj(uobject);
+}
+
+struct ib_uobject *uverbs_get_type_from_idr(const struct uverbs_type_alloc_action *type,
+					    struct ib_ucontext *ucontext,
+					    enum uverbs_idr_access access,
+					    uint32_t idr)
+{
+	struct ib_uobject *uobj;
+	int ret;
+
+	if (access == UVERBS_IDR_ACCESS_NEW) {
+		uobj = kmalloc(type->obj_size, GFP_KERNEL);
+		if (!uobj)
+			return ERR_PTR(-ENOMEM);
+
+		init_uobj(uobj, 0, ucontext);
+
+		/* lock idr */
+		ret = ib_uverbs_uobject_add(uobj, type);
+		if (ret) {
+			kfree(uobj);
+			return ERR_PTR(ret);
+		}
+
+	} else {
+		uobj = get_uobject_from_context(ucontext, type, idr,
+						access);
+
+		if (!uobj)
+			return ERR_PTR(-ENOENT);
+	}
+
+	return uobj;
+}
+
+struct ib_uobject *uverbs_get_type_from_fd(const struct uverbs_type_alloc_action *type,
+					   struct ib_ucontext *ucontext,
+					   enum uverbs_idr_access access,
+					   int fd)
+{
+	if (access == UVERBS_IDR_ACCESS_NEW) {
+		int _fd;
+		struct ib_uobject *uobj = NULL;
+		struct file *filp;
+
+		_fd = get_unused_fd_flags(O_CLOEXEC);
+		if (_fd < 0 || WARN_ON(type->obj_size < sizeof(struct ib_uobject)))
+			return ERR_PTR(_fd);
+
+		uobj = kmalloc(type->obj_size, GFP_KERNEL);
+		init_uobj(uobj, 0, ucontext);
+
+		if (!uobj)
+			return ERR_PTR(-ENOMEM);
+
+		filp = anon_inode_getfile(type->fd.name, type->fd.fops,
+					  uobj + 1, type->fd.flags);
+		if (IS_ERR(filp)) {
+			put_unused_fd(_fd);
+			kfree(uobj);
+			return (void *)filp;
+		}
+
+		uobj->type = type;
+		uobj->id = _fd;
+		uobj->object = filp;
+
+		return uobj;
+	} else if (access == UVERBS_IDR_ACCESS_READ) {
+		struct file *f = fget(fd);
+		struct ib_uobject *uobject;
+
+		if (!f)
+			return ERR_PTR(-EBADF);
+
+		uobject = f->private_data - sizeof(struct ib_uobject);
+		if (f->f_op != type->fd.fops ||
+		    !uobject->live) {
+			fput(f);
+			return ERR_PTR(-EBADF);
+		}
+
+		/*
+		 * No need to protect it with a ref count, as fget increases
+		 * f_count.
+		 */
+		return uobject;
+	} else {
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+}
+
+static void ib_uverbs_uobject_enable(struct ib_uobject *uobject)
+{
+	mutex_lock(&uobject->context->uobjects_lock->lock);
+	list_add(&uobject->list, &uobject->context->uobjects);
+	mutex_unlock(&uobject->context->uobjects_lock->lock);
+	uobject->live = 1;
+}
+
+static void ib_uverbs_uobject_remove(struct ib_uobject *uobject, bool lock)
+{
+	/*
+	 * Calling remove requires exclusive access, so it's not possible
+	 * another thread will use our object.
+	 */
+	uobject->live = 0;
+	uobject->type->free_fn(uobject->type, uobject);
+	if (lock)
+		mutex_lock(&uobject->context->uobjects_lock->lock);
+	list_del(&uobject->list);
+	if (lock)
+		mutex_unlock(&uobject->context->uobjects_lock->lock);
+	remove_uobj(uobject);
+	put_uobj(uobject);
+}
+
+static void uverbs_unlock_idr(struct ib_uobject *uobj,
+			      enum uverbs_idr_access access,
+			      bool success)
+{
+	switch (access) {
+	case UVERBS_IDR_ACCESS_READ:
+		up_read(&uobj->usecnt);
+		break;
+	case UVERBS_IDR_ACCESS_NEW:
+		if (success) {
+			ib_uverbs_uobject_enable(uobj);
+		} else {
+			remove_uobj(uobj);
+			put_uobj(uobj);
+		}
+		break;
+	case UVERBS_IDR_ACCESS_WRITE:
+		up_write(&uobj->usecnt);
+		break;
+	case UVERBS_IDR_ACCESS_DESTROY:
+		if (success)
+			ib_uverbs_uobject_remove(uobj, true);
+		else
+			up_write(&uobj->usecnt);
+		break;
+	}
+}
+
+static void uverbs_unlock_fd(struct ib_uobject *uobj,
+			     enum uverbs_idr_access access,
+			     bool success)
+{
+	struct file *filp = uobj->object;
+
+	if (access == UVERBS_IDR_ACCESS_NEW) {
+		if (success) {
+			kref_get(&uobj->context->ufile->ref);
+			uobj->uobjects_lock = uobj->context->uobjects_lock;
+			kref_get(&uobj->uobjects_lock->ref);
+			ib_uverbs_uobject_enable(uobj);
+			fd_install(uobj->id, uobj->object);
+		} else {
+			fput(uobj->object);
+			put_unused_fd(uobj->id);
+			kfree(uobj);
+		}
+	} else {
+		fput(filp);
+	}
+}
+
+void uverbs_unlock_object(struct ib_uobject *uobj,
+			  enum uverbs_idr_access access,
+			  bool success)
+{
+	if (uobj->type->type == UVERBS_ATTR_TYPE_IDR)
+		uverbs_unlock_idr(uobj, access, success);
+	else if (uobj->type->type == UVERBS_ATTR_TYPE_FD)
+		uverbs_unlock_fd(uobj, access, success);
+	else
+		WARN_ON(true);
+}
+
+static void ib_uverbs_remove_fd(struct ib_uobject *uobject)
+{
+	/*
+	 * user should release the uobject in the release
+	 * callback.
+	 */
+	if (uobject->live) {
+		uobject->live = 0;
+		list_del(&uobject->list);
+		uobject->type->free_fn(uobject->type, uobject);
+		kref_put(&uobject->context->ufile->ref, ib_uverbs_release_file);
+		uobject->context = NULL;
+	}
+}
+
+void ib_uverbs_close_fd(struct file *f)
+{
+	struct ib_uobject *uobject = f->private_data - sizeof(struct ib_uobject);
+
+	mutex_lock(&uobject->uobjects_lock->lock);
+	if (uobject->live) {
+		uobject->live = 0;
+		list_del(&uobject->list);
+		kref_put(&uobject->context->ufile->ref, ib_uverbs_release_file);
+		uobject->context = NULL;
+	}
+	mutex_unlock(&uobject->uobjects_lock->lock);
+	kref_put(&uobject->uobjects_lock->ref, release_uobjects_list_lock);
+}
+
+void ib_uverbs_cleanup_fd(void *private_data)
+{
+	struct ib_uboject *uobject = private_data - sizeof(struct ib_uobject);
+
+	kfree(uobject);
+}
+
+void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
+			   size_t num,
+			   const struct uverbs_action_spec *spec,
+			   bool success)
+{
+	unsigned int i;
+
+	for (i = 0; i < num; i++) {
+		struct uverbs_attr_array *attr_spec_array = &attr_array[i];
+		const struct uverbs_attr_group_spec *group_spec =
+			spec->attr_groups[i];
+		unsigned int j;
+
+		for (j = 0; j < attr_spec_array->num_attrs; j++) {
+			struct uverbs_attr *attr = &attr_spec_array->attrs[j];
+			struct uverbs_attr_spec *spec = &group_spec->attrs[j];
+
+			if (!attr->valid)
+				continue;
+
+			if (spec->type == UVERBS_ATTR_TYPE_IDR ||
+			    spec->type == UVERBS_ATTR_TYPE_FD)
+				/*
+				 * refcounts should be handled at the object
+				 * level and not at the uobject level.
+				 */
+				uverbs_unlock_object(attr->obj_attr.uobject,
+						     spec->obj.access, success);
+		}
+	}
+}
+
+static unsigned int get_type_orders(const struct uverbs_types_group *types_group)
+{
+	unsigned int i;
+	unsigned int max = 0;
+
+	for (i = 0; i < types_group->num_groups; i++) {
+		unsigned int j;
+		const struct uverbs_types *types = types_group->type_groups[i];
+
+		for (j = 0; j < types->num_types; j++) {
+			if (!types->types[j] || !types->types[j]->alloc)
+				continue;
+			if (types->types[j]->alloc->order > max)
+				max = types->types[j]->alloc->order;
+		}
+	}
+
+	return max;
+}
+
+void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext *ucontext,
+					     const struct uverbs_types_group *types_group)
+{
+	unsigned int num_orders = get_type_orders(types_group);
+	unsigned int i;
+
+	for (i = 0; i <= num_orders; i++) {
+		struct ib_uobject *obj, *next_obj;
+
+		/*
+		 * No need to take lock here, as cleanup should be called
+		 * after all commands finished executing. Newly executed
+		 * commands should fail.
+		 */
+		mutex_lock(&ucontext->uobjects_lock->lock);
+		list_for_each_entry_safe(obj, next_obj, &ucontext->uobjects,
+					 list)
+			if (obj->type->order == i) {
+				if (obj->type->type == UVERBS_ATTR_TYPE_IDR)
+					ib_uverbs_uobject_remove(obj, false);
+				else
+					ib_uverbs_remove_fd(obj);
+			}
+		mutex_unlock(&ucontext->uobjects_lock->lock);
+	}
+	kref_put(&ucontext->uobjects_lock->ref, release_uobjects_list_lock);
+}
+
+int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext *ucontext)
+{
+	ucontext->uobjects_lock = kmalloc(sizeof(*ucontext->uobjects_lock),
+					  GFP_KERNEL);
+	if (!ucontext->uobjects_lock)
+		return -ENOMEM;
+
+	init_uobjects_list_lock(ucontext->uobjects_lock);
+	INIT_LIST_HEAD(&ucontext->uobjects);
+
+	return 0;
+}
+
+void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext *ucontext)
+{
+	kfree(ucontext->uobjects_lock);
+}
+
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
new file mode 100644
index 0000000..8990115
--- /dev/null
+++ b/drivers/infiniband/core/rdma_core.h
@@ -0,0 +1,75 @@ 
+/*
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005-2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef UOBJECT_H
+#define UOBJECT_H
+
+#include <linux/idr.h>
+#include <rdma/uverbs_ioctl.h>
+#include <rdma/ib_verbs.h>
+#include <linux/mutex.h>
+
+const struct uverbs_type *uverbs_get_type(const struct ib_device *ibdev,
+					  uint16_t type);
+struct ib_uobject *uverbs_get_type_from_idr(const struct uverbs_type_alloc_action *type,
+					    struct ib_ucontext *ucontext,
+					    enum uverbs_idr_access access,
+					    uint32_t idr);
+struct ib_uobject *uverbs_get_type_from_fd(const struct uverbs_type_alloc_action *type,
+					   struct ib_ucontext *ucontext,
+					   enum uverbs_idr_access access,
+					   int fd);
+void uverbs_unlock_object(struct ib_uobject *uobj,
+			  enum uverbs_idr_access access,
+			  bool success);
+void uverbs_unlock_objects(struct uverbs_attr_array *attr_array,
+			   size_t num,
+			   const struct uverbs_action_spec *spec,
+			   bool success);
+
+void ib_uverbs_uobject_type_cleanup_ucontext(struct ib_ucontext *ucontext,
+					     const struct uverbs_types_group *types_group);
+int ib_uverbs_uobject_type_initialize_ucontext(struct ib_ucontext *ucontext);
+void ib_uverbs_uobject_type_release_ucontext(struct ib_ucontext *ucontext);
+void ib_uverbs_close_fd(struct file *f);
+void ib_uverbs_cleanup_fd(void *private_data);
+
+static inline void *uverbs_fd_to_priv(struct ib_uobject *uobj)
+{
+	return uobj + 1;
+}
+
+#endif /* UIDR_H */
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 8074705..ae7d4b8 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -180,6 +180,7 @@  void idr_remove_uobj(struct ib_uobject *uobj);
 struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
 					struct ib_device *ib_dev,
 					int is_async);
+void ib_uverbs_release_file(struct kref *ref);
 void ib_uverbs_free_async_event_file(struct ib_uverbs_file *uverbs_file);
 struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
 
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index f783723..e63357a 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -341,7 +341,7 @@  static void ib_uverbs_comp_dev(struct ib_uverbs_device *dev)
 	complete(&dev->comp);
 }
 
-static void ib_uverbs_release_file(struct kref *ref)
+void ib_uverbs_release_file(struct kref *ref)
 {
 	struct ib_uverbs_file *file =
 		container_of(ref, struct ib_uverbs_file, ref);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index b5d2075..7240615 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1329,8 +1329,11 @@  struct ib_fmr_attr {
 
 struct ib_umem;
 
+struct ib_ucontext_lock;
+
 struct ib_ucontext {
 	struct ib_device       *device;
+	struct ib_uverbs_file  *ufile;
 	struct list_head	pd_list;
 	struct list_head	mr_list;
 	struct list_head	mw_list;
@@ -1344,6 +1347,10 @@  struct ib_ucontext {
 	struct list_head	rwq_ind_tbl_list;
 	int			closing;
 
+	/* lock for uobjects list */
+	struct ib_ucontext_lock	*uobjects_lock;
+	struct list_head	uobjects;
+
 	struct pid             *tgid;
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
 	struct rb_root      umem_tree;
@@ -1363,16 +1370,28 @@  struct ib_ucontext {
 #endif
 };
 
+struct uverbs_object_list;
+
+#define OLD_ABI_COMPAT
+
 struct ib_uobject {
 	u64			user_handle;	/* handle given to us by userspace */
 	struct ib_ucontext     *context;	/* associated user context */
 	void		       *object;		/* containing object */
 	struct list_head	list;		/* link to context's list */
-	int			id;		/* index into kernel idr */
-	struct kref		ref;
-	struct rw_semaphore	mutex;		/* protects .live */
+	int			id;		/* index into kernel idr/fd */
+#ifdef OLD_ABI_COMPAT
+	struct kref             ref;
+#endif
+	struct rw_semaphore	usecnt;		/* protects exclusive access */
+#ifdef OLD_ABI_COMPAT
+	struct rw_semaphore     mutex;          /* protects .live */
+#endif
 	struct rcu_head		rcu;		/* kfree_rcu() overhead */
 	int			live;
+
+	const struct uverbs_type_alloc_action *type;
+	struct ib_ucontext_lock	*uobjects_lock;
 };
 
 struct ib_udata {
@@ -2101,6 +2120,9 @@  struct ib_device {
 	 */
 	int (*get_port_immutable)(struct ib_device *, u8, struct ib_port_immutable *);
 	void (*get_dev_fw_str)(struct ib_device *, char *str, size_t str_len);
+	struct list_head type_list;
+
+	const struct uverbs_types_group	*types_group;
 };
 
 struct ib_client {
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
new file mode 100644
index 0000000..2f50045
--- /dev/null
+++ b/include/rdma/uverbs_ioctl.h
@@ -0,0 +1,195 @@ 
+/*
+ * Copyright (c) 2016, Mellanox Technologies inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _UVERBS_IOCTL_
+#define _UVERBS_IOCTL_
+
+#include <linux/kernel.h>
+
+struct uverbs_object_type;
+struct ib_ucontext;
+struct ib_uobject;
+struct ib_device;
+struct uverbs_uobject_type;
+
+/*
+ * =======================================
+ *	Verbs action specifications
+ * =======================================
+ */
+
+enum uverbs_attr_type {
+	UVERBS_ATTR_TYPE_PTR_IN,
+	UVERBS_ATTR_TYPE_PTR_OUT,
+	UVERBS_ATTR_TYPE_IDR,
+	UVERBS_ATTR_TYPE_FD,
+};
+
+enum uverbs_idr_access {
+	UVERBS_IDR_ACCESS_READ,
+	UVERBS_IDR_ACCESS_WRITE,
+	UVERBS_IDR_ACCESS_NEW,
+	UVERBS_IDR_ACCESS_DESTROY
+};
+
+struct uverbs_attr_spec {
+	u16				len;
+	enum uverbs_attr_type		type;
+	struct {
+		u16			obj_type;
+		u8			access;
+	} obj;
+};
+
+struct uverbs_attr_group_spec {
+	struct uverbs_attr_spec		*attrs;
+	size_t				num_attrs;
+};
+
+struct uverbs_action_spec {
+	const struct uverbs_attr_group_spec		**attr_groups;
+	/* if > 0 -> validator, otherwise, error */
+	int (*dist)(__u16 *attr_id, void *priv);
+	void						*priv;
+	size_t						num_groups;
+};
+
+struct uverbs_attr_array;
+struct ib_uverbs_file;
+
+struct uverbs_action {
+	struct uverbs_action_spec spec;
+	void *priv;
+	int (*handler)(struct ib_device *ib_dev, struct ib_uverbs_file *ufile,
+		       struct uverbs_attr_array *ctx, size_t num, void *priv);
+};
+
+struct uverbs_type_alloc_action;
+typedef void (*free_type)(const struct uverbs_type_alloc_action *uobject_type,
+			  struct ib_uobject *uobject);
+
+struct uverbs_type_alloc_action {
+	enum uverbs_attr_type		type;
+	int				order;
+	size_t				obj_size;
+	free_type			free_fn;
+	struct {
+		const struct file_operations	*fops;
+		const char			*name;
+		int				flags;
+	} fd;
+};
+
+struct uverbs_type_actions_group {
+	size_t					num_actions;
+	const struct uverbs_action		**actions;
+};
+
+struct uverbs_type {
+	size_t					num_groups;
+	const struct uverbs_type_actions_group	**action_groups;
+	const struct uverbs_type_alloc_action	*alloc;
+	int (*dist)(__u16 *action_id, void *priv);
+	void					*priv;
+};
+
+struct uverbs_types {
+	size_t					num_types;
+	const struct uverbs_type		**types;
+};
+
+struct uverbs_types_group {
+	const struct uverbs_types		**type_groups;
+	size_t					num_groups;
+	int (*dist)(__u16 *type_id, void *priv);
+	void					*priv;
+};
+
+/* =================================================
+ *              Parsing infrastructure
+ * =================================================
+ */
+
+struct uverbs_ptr_attr {
+	void	* __user ptr;
+	__u16		len;
+};
+
+struct uverbs_fd_attr {
+	int		fd;
+};
+
+struct uverbs_uobj_attr {
+	/*  idr handle */
+	__u32	idr;
+};
+
+struct uverbs_obj_attr {
+	/* pointer to the kernel descriptor -> type, access, etc */
+	const struct uverbs_attr_spec *val;
+	struct ib_uverbs_attr __user	*uattr;
+	const struct uverbs_type_alloc_action	*type;
+	struct ib_uobject		*uobject;
+	union {
+		struct uverbs_fd_attr		fd;
+		struct uverbs_uobj_attr		uobj;
+	};
+};
+
+struct uverbs_attr {
+	bool valid;
+	union {
+		struct uverbs_ptr_attr	cmd_attr;
+		struct uverbs_obj_attr	obj_attr;
+	};
+};
+
+/* output of one validator */
+struct uverbs_attr_array {
+	size_t num_attrs;
+	/* arrays of attrubytes, index is the id i.e SEND_CQ */
+	struct uverbs_attr *attrs;
+};
+
+/* =================================================
+ *              Types infrastructure
+ * =================================================
+ */
+
+int ib_uverbs_uobject_type_add(struct list_head	*head,
+			       void (*free)(struct uverbs_uobject_type *type,
+					    struct ib_uobject *uobject,
+					    struct ib_ucontext *ucontext),
+			       uint16_t	obj_type);
+void ib_uverbs_uobject_types_remove(struct ib_device *ib_dev);
+
+#endif