[PATCH 06/27] drm/etnaviv: get rid of userptr worker

Russell King - ARM Linux linux at armlinux.org.uk
Fri Dec 1 16:51:05 UTC 2017


On Fri, Dec 01, 2017 at 05:38:51PM +0100, Philipp Zabel wrote:
> On Fri, 2017-12-01 at 11:36 +0100, Lucas Stach wrote:
> > All code paths which populate userptr BOs are fine with the get_pages
> > function taking the mmap_sem lock. This allows to get rid of the pretty
> > involved architecture with a worker being scheduled if the mmap_sem
> > needs to be taken, but instead call GUP directly and allow it to take
> > the lock if necessary.
> > 
> > This simplifies the code a lot and removes the possibility of this
> > function returning -EAGAIN, which complicates object population
> > handling at the callers.
> > 
> > Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
> > ---
> >  drivers/gpu/drm/etnaviv/etnaviv_gem.c | 146 +++++-----------------------------
> >  drivers/gpu/drm/etnaviv/etnaviv_gem.h |   3 +-
> >  2 files changed, 23 insertions(+), 126 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> > index a52220eeee45..fcc969fa0e69 100644
> > --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> > +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> > @@ -705,141 +705,41 @@ int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags,
> >  	return 0;
> >  }
> >  
> > -struct get_pages_work {
> > -	struct work_struct work;
> > -	struct mm_struct *mm;
> > -	struct task_struct *task;
> > -	struct etnaviv_gem_object *etnaviv_obj;
> > -};
> > -
> > -static struct page **etnaviv_gem_userptr_do_get_pages(
> > -	struct etnaviv_gem_object *etnaviv_obj, struct mm_struct *mm, struct task_struct *task)
> > -{
> > -	int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> > -	struct page **pvec;
> > -	uintptr_t ptr;
> > -	unsigned int flags = 0;
> > -
> > -	pvec = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
> > -	if (!pvec)
> > -		return ERR_PTR(-ENOMEM);
> > -
> > -	if (!etnaviv_obj->userptr.ro)
> > -		flags |= FOLL_WRITE;
> > -
> > -	pinned = 0;
> > -	ptr = etnaviv_obj->userptr.ptr;
> > -
> > -	down_read(&mm->mmap_sem);
> > -	while (pinned < npages) {
> > -		ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
> > -					    flags, pvec + pinned, NULL, NULL);
> > -		if (ret < 0)
> > -			break;
> > -
> > -		ptr += ret * PAGE_SIZE;
> > -		pinned += ret;
> > -	}
> > -	up_read(&mm->mmap_sem);
> > -
> > -	if (ret < 0) {
> > -		release_pages(pvec, pinned);
> > -		kvfree(pvec);
> > -		return ERR_PTR(ret);
> > -	}
> > -
> > -	return pvec;
> > -}
> > -
> > -static void __etnaviv_gem_userptr_get_pages(struct work_struct *_work)
> > -{
> > -	struct get_pages_work *work = container_of(_work, typeof(*work), work);
> > -	struct etnaviv_gem_object *etnaviv_obj = work->etnaviv_obj;
> > -	struct page **pvec;
> > -
> > -	pvec = etnaviv_gem_userptr_do_get_pages(etnaviv_obj, work->mm, work->task);
> > -
> > -	mutex_lock(&etnaviv_obj->lock);
> > -	if (IS_ERR(pvec)) {
> > -		etnaviv_obj->userptr.work = ERR_CAST(pvec);
> > -	} else {
> > -		etnaviv_obj->userptr.work = NULL;
> > -		etnaviv_obj->pages = pvec;
> > -	}
> > -
> > -	mutex_unlock(&etnaviv_obj->lock);
> > -	drm_gem_object_put_unlocked(&etnaviv_obj->base);
> > -
> > -	mmput(work->mm);
> > -	put_task_struct(work->task);
> > -	kfree(work);
> > -}
> > -
> >  static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj)
> >  {
> >  	struct page **pvec = NULL;
> > -	struct get_pages_work *work;
> > -	struct mm_struct *mm;
> > -	int ret, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> > +	struct etnaviv_gem_userptr *userptr = &etnaviv_obj->userptr;
> > +	int ret, pinned = 0, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> >  
> >  	might_lock_read(&current->mm->mmap_sem);
> >  
> > -	if (etnaviv_obj->userptr.work) {
> > -		if (IS_ERR(etnaviv_obj->userptr.work)) {
> > -			ret = PTR_ERR(etnaviv_obj->userptr.work);
> > -			etnaviv_obj->userptr.work = NULL;
> > -		} else {
> > -			ret = -EAGAIN;
> > -		}
> > -		return ret;
> > -	}
> > +	if (userptr->mm != current->mm)
> > +		return -EPERM;
> 
> I don't pretend to understand the implications of this patch completely.
> It looks mostly good to me, but this part seems to limit previously
> allowed behaviour. I think this warrants a mention in the commit
> message.

The point of the complexity is to be able to grab the mmap_sem avoiding
any locking dependencies that would normally occur if it were done in
the ioctl.

However, drm locking has changed quite a bit over the last year, and
this is probably not be needed anymore - I assume that Lucas has
thoroughly verified the locking dependencies.  However, I notice i915
still retains this code though.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


More information about the dri-devel mailing list