Re: [PATCH 10/32] uverbs: Convert idr to XArray

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Feb 20, 2019 at 04:20:45PM -0800, Matthew Wilcox wrote:
> The word 'idr' is scattered throughout the API, so I haven't changed it,
> but the 'idr' variable is now an XArray.
> 
> Signed-off-by: Matthew Wilcox <willy@xxxxxxxxxxxxx>
>  drivers/infiniband/core/rdma_core.c | 78 +++++++----------------------
>  drivers/infiniband/core/uverbs.h    |  4 +-
>  2 files changed, 18 insertions(+), 64 deletions(-)
> 
> diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c
> index 6c4747e61d2b..1084685ddce7 100644
> +++ b/drivers/infiniband/core/rdma_core.c
> @@ -296,25 +296,8 @@ static struct ib_uobject *alloc_uobj(struct ib_uverbs_file *ufile,
>  
>  static int idr_add_uobj(struct ib_uobject *uobj)
>  {
> -	int ret;
> -
> -	idr_preload(GFP_KERNEL);
> -	spin_lock(&uobj->ufile->idr_lock);
> -
> -	/*
> -	 * We start with allocating an idr pointing to NULL. This represents an
> -	 * object which isn't initialized yet. We'll replace it later on with
> -	 * the real object once we commit.
> -	 */
> -	ret = idr_alloc(&uobj->ufile->idr, NULL, 0,
> -			min_t(unsigned long, U32_MAX - 1, INT_MAX), GFP_NOWAIT);
> -	if (ret >= 0)
> -		uobj->id = ret;
> -
> -	spin_unlock(&uobj->ufile->idr_lock);
> -	idr_preload_end();
> -
> -	return ret < 0 ? ret : 0;
> +	return xa_alloc(&uobj->ufile->idr, &uobj->id, uobj, xa_limit_32b,
> +			GFP_KERNEL);

This really does need to store NULL here. We can't allow
lookup_get_idr_uobject to see the pointer until the object is
compelted initialized.. The basic high level flow is something like

xa_alloc(&id, XA_ZERO_ENTRY)
copy_to_user(id)
xa_store(id, uobj);

Where the xa_store must only happen if the copy_to_user succeeded.

>  }
>  
>  /* Returns the ib_uobject or an error. The caller should check for IS_ERR. */
> @@ -324,29 +307,14 @@ lookup_get_idr_uobject(const struct uverbs_api_object *obj,
>  		       enum rdma_lookup_mode mode)
>  {
>  	struct ib_uobject *uobj;
> -	unsigned long idrno = id;
>  
> -	if (id < 0 || id > ULONG_MAX)
> +	if ((u64)id > ULONG_MAX)
>  		return ERR_PTR(-EINVAL);

'id' is controlled by userspace, negative values in the s64 are
strictly forbidden, so this isn't an equivalent transformation.

> @@ -587,16 +549,11 @@ static int alloc_commit_idr_uobject(struct ib_uobject *uobj)
>  {
>  	struct ib_uverbs_file *ufile = uobj->ufile;
>  
> -	spin_lock(&ufile->idr_lock);
>  	/*
> -	 * We already allocated this IDR with a NULL object, so
> -	 * this shouldn't fail.
> -	 *
> -	 * NOTE: Once we set the IDR we loose ownership of our kref on uobj.
> +	 * NOTE: Storing the uobj transfers our kref on uobj to the XArray.
>  	 * It will be put by remove_commit_idr_uobject()
>  	 */
> -	WARN_ON(idr_replace(&ufile->idr, uobj, uobj->id));
> -	spin_unlock(&ufile->idr_lock);
> +	xa_store(&ufile->idr, uobj->id, uobj, 0);

What does the GFP flags == 0 do? I've seen you use this as a marker
for stores that cannot fail?

IMHO it would be nice to have a xa_store_reserved() idea which returns
void and WARNS_ON if it is mis-used.

Jason



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux