diff mbox series

[v2] drm/gem: Fix mmap fake offset handling for drm_gem_object_funcs.mmap

Message ID 20191024191859.31700-1-robh@kernel.org (mailing list archive)
State New, archived
Headers show
Series [v2] drm/gem: Fix mmap fake offset handling for drm_gem_object_funcs.mmap | expand

Commit Message

Rob Herring Oct. 24, 2019, 7:18 p.m. UTC
Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
introduced a GEM object mmap() hook which is expected to subtract the
fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
a fake offset.

To fix this, let's always call mmap() object callback with an offset of 0,
and leave it up to drm_gem_mmap_obj() to remove the fake offset.

TTM still needs the fake offset, so we have to add it back until that's
fixed.

Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Rob Herring <robh@kernel.org>
---
v2:
- Move subtracting the fake offset out of mmap() obj callbacks.

I've tested shmem, but not ttm. Hopefully, I understood what's needed 
for TTM.

Rob

 drivers/gpu/drm/drm_gem.c              | 3 +++
 drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ---
 drivers/gpu/drm/ttm/ttm_bo_vm.c        | 7 +++++++
 include/drm/drm_gem.h                  | 4 +++-
 4 files changed, 13 insertions(+), 4 deletions(-)

Comments

Gerd Hoffmann Oct. 25, 2019, 5:34 a.m. UTC | #1
On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> introduced a GEM object mmap() hook which is expected to subtract the
> fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> a fake offset.
> 
> To fix this, let's always call mmap() object callback with an offset of 0,
> and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> 
> TTM still needs the fake offset, so we have to add it back until that's
> fixed.

Fixing ttm looks easy, there are not many calls to drm_vma_node_start()
the ttm code.  Can look into this when I'm back from kvm forum @ lyon.

>  int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
>  {
>  	ttm_bo_get(bo);
> +
> +	/*
> +	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
> +	 * removed. Add it back here until the rest of TTM works without it.
> +	 */
> +	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
> +
>  	ttm_bo_mmap_vma_setup(bo, vma);
>  	return 0;
>  }

Yes, that should keep ttm happy for now.  Survived a quick smoke test
with qemu and bochs.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>

cheers,
  Gerd
Daniel Vetter Oct. 25, 2019, 7:30 a.m. UTC | #2
On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> introduced a GEM object mmap() hook which is expected to subtract the
> fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> a fake offset.
> 
> To fix this, let's always call mmap() object callback with an offset of 0,
> and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> 
> TTM still needs the fake offset, so we have to add it back until that's
> fixed.
> 
> Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> v2:
> - Move subtracting the fake offset out of mmap() obj callbacks.
> 
> I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> for TTM.
> 
> Rob
> 
>  drivers/gpu/drm/drm_gem.c              | 3 +++
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ---
>  drivers/gpu/drm/ttm/ttm_bo_vm.c        | 7 +++++++
>  include/drm/drm_gem.h                  | 4 +++-
>  4 files changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index 56f42e0f2584..2f2b889096b0 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -1106,6 +1106,9 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
>  		return -EINVAL;
>  
>  	if (obj->funcs && obj->funcs->mmap) {
> +		/* Remove the fake offset */
> +		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
> +
>  		ret = obj->funcs->mmap(obj, vma);
>  		if (ret)
>  			return ret;
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index a878c787b867..e8061c64c480 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -542,9 +542,6 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
>  	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
>  	vma->vm_ops = &drm_gem_shmem_vm_ops;
>  
> -	/* Remove the fake offset */
> -	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
> -
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
> diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> index 1a9db691f954..08902c7290a5 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> @@ -482,6 +482,13 @@ EXPORT_SYMBOL(ttm_bo_mmap);
>  int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
>  {
>  	ttm_bo_get(bo);
> +
> +	/*
> +	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
> +	 * removed. Add it back here until the rest of TTM works without it.
> +	 */
> +	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
> +
>  	ttm_bo_mmap_vma_setup(bo, vma);
>  	return 0;
>  }
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index e71f75a2ab57..c56cbb3509e0 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -159,7 +159,9 @@ struct drm_gem_object_funcs {
>  	 *
>  	 * The callback is used by by both drm_gem_mmap_obj() and
>  	 * drm_gem_prime_mmap().  When @mmap is present @vm_ops is not
> -	 * used, the @mmap callback must set vma->vm_ops instead.
> +	 * used, the @mmap callback must set vma->vm_ops instead. The @mmap
> +	 * callback is always called with a 0 offset. The caller will remove
> +	 * the fake offset as necessary.
>  	 *

Maybe remove this empty comment line here while at it. With that

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

I think I'll follow up with a patch to annotate drm_gem_mmap_obj as
deprecated and that instead this here should be used.
-Daniel

>  	 */
>  	int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
> -- 
> 2.20.1
>
Daniel Vetter Nov. 8, 2019, 4:27 p.m. UTC | #3
On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > introduced a GEM object mmap() hook which is expected to subtract the
> > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > a fake offset.
> > 
> > To fix this, let's always call mmap() object callback with an offset of 0,
> > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > 
> > TTM still needs the fake offset, so we have to add it back until that's
> > fixed.
> > 
> > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > Signed-off-by: Rob Herring <robh@kernel.org>
> > ---
> > v2:
> > - Move subtracting the fake offset out of mmap() obj callbacks.
> > 
> > I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> > for TTM.

So unfortunately I'm already having regrets on this. We might even have
broken some of the ttm drivers here.

Trouble is, if you need to shoot down userspace ptes of a bo (because it's
getting moved or whatever), then we do that with unmap_mapping_range.
Which means each bo needs to be mapping with a unique (offset,
adress_space), or it won't work. By remapping all the bo to 0 we've broken
this. We've also had this broken this for a while for the simplistic
dma-buf mmap, since without any further action we'll reuse the address
space of the dma-buf inode, not of the drm_device.

Strangely both etnaviv and msm have a comment to that effect - grep for
unmap_mapping_range. But neither actually uses it.

Not exactly sure what's the best course of action here now.

Also adding Thomas Zimmermann, who's worked on all the vram helpers.
-Daniel

> > 
> > Rob
> > 
> >  drivers/gpu/drm/drm_gem.c              | 3 +++
> >  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ---
> >  drivers/gpu/drm/ttm/ttm_bo_vm.c        | 7 +++++++
> >  include/drm/drm_gem.h                  | 4 +++-
> >  4 files changed, 13 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> > index 56f42e0f2584..2f2b889096b0 100644
> > --- a/drivers/gpu/drm/drm_gem.c
> > +++ b/drivers/gpu/drm/drm_gem.c
> > @@ -1106,6 +1106,9 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
> >  		return -EINVAL;
> >  
> >  	if (obj->funcs && obj->funcs->mmap) {
> > +		/* Remove the fake offset */
> > +		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
> > +
> >  		ret = obj->funcs->mmap(obj, vma);
> >  		if (ret)
> >  			return ret;
> > diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> > index a878c787b867..e8061c64c480 100644
> > --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> > +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> > @@ -542,9 +542,6 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
> >  	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> >  	vma->vm_ops = &drm_gem_shmem_vm_ops;
> >  
> > -	/* Remove the fake offset */
> > -	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
> > -
> >  	return 0;
> >  }
> >  EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
> > diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> > index 1a9db691f954..08902c7290a5 100644
> > --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
> > +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> > @@ -482,6 +482,13 @@ EXPORT_SYMBOL(ttm_bo_mmap);
> >  int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
> >  {
> >  	ttm_bo_get(bo);
> > +
> > +	/*
> > +	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
> > +	 * removed. Add it back here until the rest of TTM works without it.
> > +	 */
> > +	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
> > +
> >  	ttm_bo_mmap_vma_setup(bo, vma);
> >  	return 0;
> >  }
> > diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> > index e71f75a2ab57..c56cbb3509e0 100644
> > --- a/include/drm/drm_gem.h
> > +++ b/include/drm/drm_gem.h
> > @@ -159,7 +159,9 @@ struct drm_gem_object_funcs {
> >  	 *
> >  	 * The callback is used by by both drm_gem_mmap_obj() and
> >  	 * drm_gem_prime_mmap().  When @mmap is present @vm_ops is not
> > -	 * used, the @mmap callback must set vma->vm_ops instead.
> > +	 * used, the @mmap callback must set vma->vm_ops instead. The @mmap
> > +	 * callback is always called with a 0 offset. The caller will remove
> > +	 * the fake offset as necessary.
> >  	 *
> 
> Maybe remove this empty comment line here while at it. With that
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> I think I'll follow up with a patch to annotate drm_gem_mmap_obj as
> deprecated and that instead this here should be used.
> -Daniel
> 
> >  	 */
> >  	int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
> > -- 
> > 2.20.1
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
Daniel Vetter Nov. 8, 2019, 4:55 p.m. UTC | #4
On Fri, Nov 08, 2019 at 05:27:59PM +0100, Daniel Vetter wrote:
> On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > introduced a GEM object mmap() hook which is expected to subtract the
> > > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > > a fake offset.
> > > 
> > > To fix this, let's always call mmap() object callback with an offset of 0,
> > > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > > 
> > > TTM still needs the fake offset, so we have to add it back until that's
> > > fixed.
> > > 
> > > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > ---
> > > v2:
> > > - Move subtracting the fake offset out of mmap() obj callbacks.
> > > 
> > > I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> > > for TTM.
> 
> So unfortunately I'm already having regrets on this. We might even have
> broken some of the ttm drivers here.
> 
> Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> getting moved or whatever), then we do that with unmap_mapping_range.
> Which means each bo needs to be mapping with a unique (offset,
> adress_space), or it won't work. By remapping all the bo to 0 we've broken
> this. We've also had this broken this for a while for the simplistic
> dma-buf mmap, since without any further action we'll reuse the address
> space of the dma-buf inode, not of the drm_device.
> 
> Strangely both etnaviv and msm have a comment to that effect - grep for
> unmap_mapping_range. But neither actually uses it.
> 
> Not exactly sure what's the best course of action here now.
> 
> Also adding Thomas Zimmermann, who's worked on all the vram helpers.

Correction, I missed the unmap_mapping_range in the vma node manager
header, so didn't spot the drivers using drm_vma_node_unmap. We did break
all the ttm stuff :-/

Plus panfrost, which is using drm_gem_shmem_purge_locked.
-Daniel

> -Daniel
> 
> > > 
> > > Rob
> > > 
> > >  drivers/gpu/drm/drm_gem.c              | 3 +++
> > >  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ---
> > >  drivers/gpu/drm/ttm/ttm_bo_vm.c        | 7 +++++++
> > >  include/drm/drm_gem.h                  | 4 +++-
> > >  4 files changed, 13 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> > > index 56f42e0f2584..2f2b889096b0 100644
> > > --- a/drivers/gpu/drm/drm_gem.c
> > > +++ b/drivers/gpu/drm/drm_gem.c
> > > @@ -1106,6 +1106,9 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
> > >  		return -EINVAL;
> > >  
> > >  	if (obj->funcs && obj->funcs->mmap) {
> > > +		/* Remove the fake offset */
> > > +		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
> > > +
> > >  		ret = obj->funcs->mmap(obj, vma);
> > >  		if (ret)
> > >  			return ret;
> > > diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> > > index a878c787b867..e8061c64c480 100644
> > > --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> > > +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> > > @@ -542,9 +542,6 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
> > >  	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> > >  	vma->vm_ops = &drm_gem_shmem_vm_ops;
> > >  
> > > -	/* Remove the fake offset */
> > > -	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
> > > -
> > >  	return 0;
> > >  }
> > >  EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
> > > diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> > > index 1a9db691f954..08902c7290a5 100644
> > > --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
> > > +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> > > @@ -482,6 +482,13 @@ EXPORT_SYMBOL(ttm_bo_mmap);
> > >  int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
> > >  {
> > >  	ttm_bo_get(bo);
> > > +
> > > +	/*
> > > +	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
> > > +	 * removed. Add it back here until the rest of TTM works without it.
> > > +	 */
> > > +	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
> > > +
> > >  	ttm_bo_mmap_vma_setup(bo, vma);
> > >  	return 0;
> > >  }
> > > diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> > > index e71f75a2ab57..c56cbb3509e0 100644
> > > --- a/include/drm/drm_gem.h
> > > +++ b/include/drm/drm_gem.h
> > > @@ -159,7 +159,9 @@ struct drm_gem_object_funcs {
> > >  	 *
> > >  	 * The callback is used by by both drm_gem_mmap_obj() and
> > >  	 * drm_gem_prime_mmap().  When @mmap is present @vm_ops is not
> > > -	 * used, the @mmap callback must set vma->vm_ops instead.
> > > +	 * used, the @mmap callback must set vma->vm_ops instead. The @mmap
> > > +	 * callback is always called with a 0 offset. The caller will remove
> > > +	 * the fake offset as necessary.
> > >  	 *
> > 
> > Maybe remove this empty comment line here while at it. With that
> > 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> > I think I'll follow up with a patch to annotate drm_gem_mmap_obj as
> > deprecated and that instead this here should be used.
> > -Daniel
> > 
> > >  	 */
> > >  	int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
> > > -- 
> > > 2.20.1
> > > 
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
Gerd Hoffmann Nov. 12, 2019, 8:52 a.m. UTC | #5
On Fri, Nov 08, 2019 at 05:55:28PM +0100, Daniel Vetter wrote:
> On Fri, Nov 08, 2019 at 05:27:59PM +0100, Daniel Vetter wrote:
> > On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > > On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > > > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > introduced a GEM object mmap() hook which is expected to subtract the
> > > > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > > > a fake offset.
> > > > 
> > > > To fix this, let's always call mmap() object callback with an offset of 0,
> > > > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > > > 
> > > > TTM still needs the fake offset, so we have to add it back until that's
> > > > fixed.
> > > > 
> > > > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > > ---
> > > > v2:
> > > > - Move subtracting the fake offset out of mmap() obj callbacks.
> > > > 
> > > > I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> > > > for TTM.
> > 
> > So unfortunately I'm already having regrets on this. We might even have
> > broken some of the ttm drivers here.
> > 
> > Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > getting moved or whatever), then we do that with unmap_mapping_range.
> > Which means each bo needs to be mapping with a unique (offset,
> > adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > this. We've also had this broken this for a while for the simplistic
> > dma-buf mmap, since without any further action we'll reuse the address
> > space of the dma-buf inode, not of the drm_device.
> > 
> > Strangely both etnaviv and msm have a comment to that effect - grep for
> > unmap_mapping_range. But neither actually uses it.
> > 
> > Not exactly sure what's the best course of action here now.
> > 
> > Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> 
> Correction, I missed the unmap_mapping_range in the vma node manager
> header, so didn't spot the drivers using drm_vma_node_unmap. We did break
> all the ttm stuff :-/

ttm still uses the offset, now added in ttm_bo_mmap_obj().  So, for
normal mmap behavior did not change I think.  The simplistic dma-buf
mmap did change, it now uses the offset because it goes through
ttm_bo_mmap_obj() too.

Not fully sure which address space is used for dma-bufs though.  As far
I can see neither the old nor the new dma-buf mmap code path touch
vma->vm_file (unless the driver does explicitly care, like msm does in
msm_gem_mmap_obj).

> Plus panfrost, which is using drm_gem_shmem_purge_locked.

Hmm, looking at drm_gem_shmem_purge_locked I'm wondering why it uses a
mix of dev->anon_inode->i_mapping and file_inode(obj->filp)->i_mapping.

Also shmem helpers used a zero vm_pgoff before, only difference is the
change is applied in drm_gem_mmap_obj() now instead of somewhere in the
shmem helper code.

slightly confused,
  Gerd
Thomas Zimmermann Nov. 12, 2019, 9:26 a.m. UTC | #6
Hi

Am 08.11.19 um 17:27 schrieb Daniel Vetter:
> On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
>> On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
>>> Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
>>> introduced a GEM object mmap() hook which is expected to subtract the
>>> fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
>>> a fake offset.
>>>
>>> To fix this, let's always call mmap() object callback with an offset of 0,
>>> and leave it up to drm_gem_mmap_obj() to remove the fake offset.
>>>
>>> TTM still needs the fake offset, so we have to add it back until that's
>>> fixed.
>>>
>>> Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
>>> Signed-off-by: Rob Herring <robh@kernel.org>
>>> ---
>>> v2:
>>> - Move subtracting the fake offset out of mmap() obj callbacks.
>>>
>>> I've tested shmem, but not ttm. Hopefully, I understood what's needed 
>>> for TTM.
> 
> So unfortunately I'm already having regrets on this. We might even have
> broken some of the ttm drivers here.
> 
> Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> getting moved or whatever), then we do that with unmap_mapping_range.
> Which means each bo needs to be mapping with a unique (offset,
> adress_space), or it won't work. By remapping all the bo to 0 we've broken
> this. We've also had this broken this for a while for the simplistic
> dma-buf mmap, since without any further action we'll reuse the address
> space of the dma-buf inode, not of the drm_device.
> 
> Strangely both etnaviv and msm have a comment to that effect - grep for
> unmap_mapping_range. But neither actually uses it.
> 
> Not exactly sure what's the best course of action here now.
> 
> Also adding Thomas Zimmermann, who's worked on all the vram helpers.

VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
These changes should be transparent.

Best regards
Thomas

> -Daniel
> 
>>>
>>> Rob
>>>
>>>  drivers/gpu/drm/drm_gem.c              | 3 +++
>>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ---
>>>  drivers/gpu/drm/ttm/ttm_bo_vm.c        | 7 +++++++
>>>  include/drm/drm_gem.h                  | 4 +++-
>>>  4 files changed, 13 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
>>> index 56f42e0f2584..2f2b889096b0 100644
>>> --- a/drivers/gpu/drm/drm_gem.c
>>> +++ b/drivers/gpu/drm/drm_gem.c
>>> @@ -1106,6 +1106,9 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
>>>  		return -EINVAL;
>>>  
>>>  	if (obj->funcs && obj->funcs->mmap) {
>>> +		/* Remove the fake offset */
>>> +		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
>>> +
>>>  		ret = obj->funcs->mmap(obj, vma);
>>>  		if (ret)
>>>  			return ret;
>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>> index a878c787b867..e8061c64c480 100644
>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>> @@ -542,9 +542,6 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
>>>  	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
>>>  	vma->vm_ops = &drm_gem_shmem_vm_ops;
>>>  
>>> -	/* Remove the fake offset */
>>> -	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
>>> -
>>>  	return 0;
>>>  }
>>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
>>> diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
>>> index 1a9db691f954..08902c7290a5 100644
>>> --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
>>> +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
>>> @@ -482,6 +482,13 @@ EXPORT_SYMBOL(ttm_bo_mmap);
>>>  int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
>>>  {
>>>  	ttm_bo_get(bo);
>>> +
>>> +	/*
>>> +	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
>>> +	 * removed. Add it back here until the rest of TTM works without it.
>>> +	 */
>>> +	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
>>> +
>>>  	ttm_bo_mmap_vma_setup(bo, vma);
>>>  	return 0;
>>>  }
>>> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
>>> index e71f75a2ab57..c56cbb3509e0 100644
>>> --- a/include/drm/drm_gem.h
>>> +++ b/include/drm/drm_gem.h
>>> @@ -159,7 +159,9 @@ struct drm_gem_object_funcs {
>>>  	 *
>>>  	 * The callback is used by by both drm_gem_mmap_obj() and
>>>  	 * drm_gem_prime_mmap().  When @mmap is present @vm_ops is not
>>> -	 * used, the @mmap callback must set vma->vm_ops instead.
>>> +	 * used, the @mmap callback must set vma->vm_ops instead. The @mmap
>>> +	 * callback is always called with a 0 offset. The caller will remove
>>> +	 * the fake offset as necessary.
>>>  	 *
>>
>> Maybe remove this empty comment line here while at it. With that
>>
>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>
>> I think I'll follow up with a patch to annotate drm_gem_mmap_obj as
>> deprecated and that instead this here should be used.
>> -Daniel
>>
>>>  	 */
>>>  	int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
>>> -- 
>>> 2.20.1
>>>
>>
>> -- 
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> http://blog.ffwll.ch
>
Daniel Vetter Nov. 12, 2019, 9:32 a.m. UTC | #7
On Tue, Nov 12, 2019 at 10:26:44AM +0100, Thomas Zimmermann wrote:
> Hi
> 
> Am 08.11.19 um 17:27 schrieb Daniel Vetter:
> > On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> >> On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> >>> Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> >>> introduced a GEM object mmap() hook which is expected to subtract the
> >>> fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> >>> a fake offset.
> >>>
> >>> To fix this, let's always call mmap() object callback with an offset of 0,
> >>> and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> >>>
> >>> TTM still needs the fake offset, so we have to add it back until that's
> >>> fixed.
> >>>
> >>> Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> >>> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> >>> Signed-off-by: Rob Herring <robh@kernel.org>
> >>> ---
> >>> v2:
> >>> - Move subtracting the fake offset out of mmap() obj callbacks.
> >>>
> >>> I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> >>> for TTM.
> > 
> > So unfortunately I'm already having regrets on this. We might even have
> > broken some of the ttm drivers here.
> > 
> > Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > getting moved or whatever), then we do that with unmap_mapping_range.
> > Which means each bo needs to be mapping with a unique (offset,
> > adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > this. We've also had this broken this for a while for the simplistic
> > dma-buf mmap, since without any further action we'll reuse the address
> > space of the dma-buf inode, not of the drm_device.
> > 
> > Strangely both etnaviv and msm have a comment to that effect - grep for
> > unmap_mapping_range. But neither actually uses it.
> > 
> > Not exactly sure what's the best course of action here now.
> > 
> > Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> 
> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
> These changes should be transparent.

There's still the issue that for dma-buf mmap vs drm mmap you use
different f_mapping, which means ttm's pte shootdown won't work correctly
for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
be fine.
-Daniel

> 
> Best regards
> Thomas
> 
> > -Daniel
> > 
> >>>
> >>> Rob
> >>>
> >>>  drivers/gpu/drm/drm_gem.c              | 3 +++
> >>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ---
> >>>  drivers/gpu/drm/ttm/ttm_bo_vm.c        | 7 +++++++
> >>>  include/drm/drm_gem.h                  | 4 +++-
> >>>  4 files changed, 13 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> >>> index 56f42e0f2584..2f2b889096b0 100644
> >>> --- a/drivers/gpu/drm/drm_gem.c
> >>> +++ b/drivers/gpu/drm/drm_gem.c
> >>> @@ -1106,6 +1106,9 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
> >>>  		return -EINVAL;
> >>>  
> >>>  	if (obj->funcs && obj->funcs->mmap) {
> >>> +		/* Remove the fake offset */
> >>> +		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
> >>> +
> >>>  		ret = obj->funcs->mmap(obj, vma);
> >>>  		if (ret)
> >>>  			return ret;
> >>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>> index a878c787b867..e8061c64c480 100644
> >>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>> @@ -542,9 +542,6 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
> >>>  	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> >>>  	vma->vm_ops = &drm_gem_shmem_vm_ops;
> >>>  
> >>> -	/* Remove the fake offset */
> >>> -	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
> >>> -
> >>>  	return 0;
> >>>  }
> >>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
> >>> diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> >>> index 1a9db691f954..08902c7290a5 100644
> >>> --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
> >>> +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
> >>> @@ -482,6 +482,13 @@ EXPORT_SYMBOL(ttm_bo_mmap);
> >>>  int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
> >>>  {
> >>>  	ttm_bo_get(bo);
> >>> +
> >>> +	/*
> >>> +	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
> >>> +	 * removed. Add it back here until the rest of TTM works without it.
> >>> +	 */
> >>> +	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
> >>> +
> >>>  	ttm_bo_mmap_vma_setup(bo, vma);
> >>>  	return 0;
> >>>  }
> >>> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> >>> index e71f75a2ab57..c56cbb3509e0 100644
> >>> --- a/include/drm/drm_gem.h
> >>> +++ b/include/drm/drm_gem.h
> >>> @@ -159,7 +159,9 @@ struct drm_gem_object_funcs {
> >>>  	 *
> >>>  	 * The callback is used by by both drm_gem_mmap_obj() and
> >>>  	 * drm_gem_prime_mmap().  When @mmap is present @vm_ops is not
> >>> -	 * used, the @mmap callback must set vma->vm_ops instead.
> >>> +	 * used, the @mmap callback must set vma->vm_ops instead. The @mmap
> >>> +	 * callback is always called with a 0 offset. The caller will remove
> >>> +	 * the fake offset as necessary.
> >>>  	 *
> >>
> >> Maybe remove this empty comment line here while at it. With that
> >>
> >> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >>
> >> I think I'll follow up with a patch to annotate drm_gem_mmap_obj as
> >> deprecated and that instead this here should be used.
> >> -Daniel
> >>
> >>>  	 */
> >>>  	int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
> >>> -- 
> >>> 2.20.1
> >>>
> >>
> >> -- 
> >> Daniel Vetter
> >> Software Engineer, Intel Corporation
> >> http://blog.ffwll.ch
> > 
> 
> -- 
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
>
Daniel Vetter Nov. 12, 2019, 9:35 a.m. UTC | #8
On Tue, Nov 12, 2019 at 09:52:54AM +0100, Gerd Hoffmann wrote:
> On Fri, Nov 08, 2019 at 05:55:28PM +0100, Daniel Vetter wrote:
> > On Fri, Nov 08, 2019 at 05:27:59PM +0100, Daniel Vetter wrote:
> > > On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > > > On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > > > > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > introduced a GEM object mmap() hook which is expected to subtract the
> > > > > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > > > > a fake offset.
> > > > > 
> > > > > To fix this, let's always call mmap() object callback with an offset of 0,
> > > > > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > > > > 
> > > > > TTM still needs the fake offset, so we have to add it back until that's
> > > > > fixed.
> > > > > 
> > > > > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > > > ---
> > > > > v2:
> > > > > - Move subtracting the fake offset out of mmap() obj callbacks.
> > > > > 
> > > > > I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> > > > > for TTM.
> > > 
> > > So unfortunately I'm already having regrets on this. We might even have
> > > broken some of the ttm drivers here.
> > > 
> > > Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > > getting moved or whatever), then we do that with unmap_mapping_range.
> > > Which means each bo needs to be mapping with a unique (offset,
> > > adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > > this. We've also had this broken this for a while for the simplistic
> > > dma-buf mmap, since without any further action we'll reuse the address
> > > space of the dma-buf inode, not of the drm_device.
> > > 
> > > Strangely both etnaviv and msm have a comment to that effect - grep for
> > > unmap_mapping_range. But neither actually uses it.
> > > 
> > > Not exactly sure what's the best course of action here now.
> > > 
> > > Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> > 
> > Correction, I missed the unmap_mapping_range in the vma node manager
> > header, so didn't spot the drivers using drm_vma_node_unmap. We did break
> > all the ttm stuff :-/
> 
> ttm still uses the offset, now added in ttm_bo_mmap_obj().  So, for
> normal mmap behavior did not change I think.  The simplistic dma-buf
> mmap did change, it now uses the offset because it goes through
> ttm_bo_mmap_obj() too.
> 
> Not fully sure which address space is used for dma-bufs though.  As far
> I can see neither the old nor the new dma-buf mmap code path touch
> vma->vm_file (unless the driver does explicitly care, like msm does in
> msm_gem_mmap_obj).
> 
> > Plus panfrost, which is using drm_gem_shmem_purge_locked.
> 
> Hmm, looking at drm_gem_shmem_purge_locked I'm wondering why it uses a
> mix of dev->anon_inode->i_mapping and file_inode(obj->filp)->i_mapping.
> 
> Also shmem helpers used a zero vm_pgoff before, only difference is the
> change is applied in drm_gem_mmap_obj() now instead of somewhere in the
> shmem helper code.
> 
> slightly confused,

I think summary is:
- shmem helper pte shotdown is broken for all cases now with
  obj->funcs->mmap
- ttm/vram-helpers only for dma-buf mmap redirection (because of the wrong
  f/i_mapping).

Rob, are you looking into this? I guess there's two options:
- Go back to fake offset everywhere, and weep.
- Add a per-bo mapping struct, consistently use that everywhere (probably
  more work).

If we go with weeping maybe note the 2nd option as a todo item in
todo.rst?
-Daniel

>   Gerd
>
Thomas Zimmermann Nov. 12, 2019, 9:49 a.m. UTC | #9
Hi

Am 12.11.19 um 10:32 schrieb Daniel Vetter:
> On Tue, Nov 12, 2019 at 10:26:44AM +0100, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 08.11.19 um 17:27 schrieb Daniel Vetter:
>>> On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
>>>> On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
>>>>> Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
>>>>> introduced a GEM object mmap() hook which is expected to subtract the
>>>>> fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
>>>>> a fake offset.
>>>>>
>>>>> To fix this, let's always call mmap() object callback with an offset of 0,
>>>>> and leave it up to drm_gem_mmap_obj() to remove the fake offset.
>>>>>
>>>>> TTM still needs the fake offset, so we have to add it back until that's
>>>>> fixed.
>>>>>
>>>>> Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>>> Signed-off-by: Rob Herring <robh@kernel.org>
>>>>> ---
>>>>> v2:
>>>>> - Move subtracting the fake offset out of mmap() obj callbacks.
>>>>>
>>>>> I've tested shmem, but not ttm. Hopefully, I understood what's needed 
>>>>> for TTM.
>>>
>>> So unfortunately I'm already having regrets on this. We might even have
>>> broken some of the ttm drivers here.
>>>
>>> Trouble is, if you need to shoot down userspace ptes of a bo (because it's
>>> getting moved or whatever), then we do that with unmap_mapping_range.
>>> Which means each bo needs to be mapping with a unique (offset,
>>> adress_space), or it won't work. By remapping all the bo to 0 we've broken
>>> this. We've also had this broken this for a while for the simplistic
>>> dma-buf mmap, since without any further action we'll reuse the address
>>> space of the dma-buf inode, not of the drm_device.
>>>
>>> Strangely both etnaviv and msm have a comment to that effect - grep for
>>> unmap_mapping_range. But neither actually uses it.
>>>
>>> Not exactly sure what's the best course of action here now.
>>>
>>> Also adding Thomas Zimmermann, who's worked on all the vram helpers.
>>
>> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
>> These changes should be transparent.
> 
> There's still the issue that for dma-buf mmap vs drm mmap you use
> different f_mapping, which means ttm's pte shootdown won't work correctly
> for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
> be fine.

VRAM helpers don't support dmabufs.

Best regards
Thomas

> -Daniel
> 
>>
>> Best regards
>> Thomas
>>
>>> -Daniel
>>>
>>>>>
>>>>> Rob
>>>>>
>>>>>  drivers/gpu/drm/drm_gem.c              | 3 +++
>>>>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ---
>>>>>  drivers/gpu/drm/ttm/ttm_bo_vm.c        | 7 +++++++
>>>>>  include/drm/drm_gem.h                  | 4 +++-
>>>>>  4 files changed, 13 insertions(+), 4 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
>>>>> index 56f42e0f2584..2f2b889096b0 100644
>>>>> --- a/drivers/gpu/drm/drm_gem.c
>>>>> +++ b/drivers/gpu/drm/drm_gem.c
>>>>> @@ -1106,6 +1106,9 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
>>>>>  		return -EINVAL;
>>>>>  
>>>>>  	if (obj->funcs && obj->funcs->mmap) {
>>>>> +		/* Remove the fake offset */
>>>>> +		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
>>>>> +
>>>>>  		ret = obj->funcs->mmap(obj, vma);
>>>>>  		if (ret)
>>>>>  			return ret;
>>>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>>> index a878c787b867..e8061c64c480 100644
>>>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>>> @@ -542,9 +542,6 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
>>>>>  	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
>>>>>  	vma->vm_ops = &drm_gem_shmem_vm_ops;
>>>>>  
>>>>> -	/* Remove the fake offset */
>>>>> -	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
>>>>> -
>>>>>  	return 0;
>>>>>  }
>>>>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
>>>>> diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
>>>>> index 1a9db691f954..08902c7290a5 100644
>>>>> --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
>>>>> +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
>>>>> @@ -482,6 +482,13 @@ EXPORT_SYMBOL(ttm_bo_mmap);
>>>>>  int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
>>>>>  {
>>>>>  	ttm_bo_get(bo);
>>>>> +
>>>>> +	/*
>>>>> +	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
>>>>> +	 * removed. Add it back here until the rest of TTM works without it.
>>>>> +	 */
>>>>> +	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
>>>>> +
>>>>>  	ttm_bo_mmap_vma_setup(bo, vma);
>>>>>  	return 0;
>>>>>  }
>>>>> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
>>>>> index e71f75a2ab57..c56cbb3509e0 100644
>>>>> --- a/include/drm/drm_gem.h
>>>>> +++ b/include/drm/drm_gem.h
>>>>> @@ -159,7 +159,9 @@ struct drm_gem_object_funcs {
>>>>>  	 *
>>>>>  	 * The callback is used by by both drm_gem_mmap_obj() and
>>>>>  	 * drm_gem_prime_mmap().  When @mmap is present @vm_ops is not
>>>>> -	 * used, the @mmap callback must set vma->vm_ops instead.
>>>>> +	 * used, the @mmap callback must set vma->vm_ops instead. The @mmap
>>>>> +	 * callback is always called with a 0 offset. The caller will remove
>>>>> +	 * the fake offset as necessary.
>>>>>  	 *
>>>>
>>>> Maybe remove this empty comment line here while at it. With that
>>>>
>>>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>>
>>>> I think I'll follow up with a patch to annotate drm_gem_mmap_obj as
>>>> deprecated and that instead this here should be used.
>>>> -Daniel
>>>>
>>>>>  	 */
>>>>>  	int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);
>>>>> -- 
>>>>> 2.20.1
>>>>>
>>>>
>>>> -- 
>>>> Daniel Vetter
>>>> Software Engineer, Intel Corporation
>>>> http://blog.ffwll.ch
>>>
>>
>> -- 
>> Thomas Zimmermann
>> Graphics Driver Developer
>> SUSE Software Solutions Germany GmbH
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>> (HRB 36809, AG Nürnberg)
>> Geschäftsführer: Felix Imendörffer
>>
> 
> 
> 
>
Gerd Hoffmann Nov. 12, 2019, 10:38 a.m. UTC | #10
On Tue, Nov 12, 2019 at 10:49:21AM +0100, Thomas Zimmermann wrote:
> Hi
> 
> Am 12.11.19 um 10:32 schrieb Daniel Vetter:
> > On Tue, Nov 12, 2019 at 10:26:44AM +0100, Thomas Zimmermann wrote:
> >> Hi
> >>
> >> Am 08.11.19 um 17:27 schrieb Daniel Vetter:
> >>> On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> >>>> On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> >>>>> Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> >>>>> introduced a GEM object mmap() hook which is expected to subtract the
> >>>>> fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> >>>>> a fake offset.
> >>>>>
> >>>>> To fix this, let's always call mmap() object callback with an offset of 0,
> >>>>> and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> >>>>>
> >>>>> TTM still needs the fake offset, so we have to add it back until that's
> >>>>> fixed.
> >>>>>
> >>>>> Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> >>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
> >>>>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> >>>>> Signed-off-by: Rob Herring <robh@kernel.org>
> >>>>> ---
> >>>>> v2:
> >>>>> - Move subtracting the fake offset out of mmap() obj callbacks.
> >>>>>
> >>>>> I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> >>>>> for TTM.
> >>>
> >>> So unfortunately I'm already having regrets on this. We might even have
> >>> broken some of the ttm drivers here.
> >>>
> >>> Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> >>> getting moved or whatever), then we do that with unmap_mapping_range.
> >>> Which means each bo needs to be mapping with a unique (offset,
> >>> adress_space), or it won't work. By remapping all the bo to 0 we've broken
> >>> this. We've also had this broken this for a while for the simplistic
> >>> dma-buf mmap, since without any further action we'll reuse the address
> >>> space of the dma-buf inode, not of the drm_device.
> >>>
> >>> Strangely both etnaviv and msm have a comment to that effect - grep for
> >>> unmap_mapping_range. But neither actually uses it.
> >>>
> >>> Not exactly sure what's the best course of action here now.
> >>>
> >>> Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> >>
> >> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
> >> These changes should be transparent.
> > 
> > There's still the issue that for dma-buf mmap vs drm mmap you use
> > different f_mapping, which means ttm's pte shootdown won't work correctly
> > for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
> > be fine.
> 
> VRAM helpers don't support dmabufs.

It's not that simple.  Even when not supporting dma-buf export and
import it is still possible to create dma-bufs, import them into the
same driver (which doesn't actually export+import but just grabs a gem
object reference instead) and also to mmap them via prime/dma-buf code
path ...

Can ttm use the same trick msm uses?  Now that ttm bo's are a gem object
superclass I think we should be able to switch vma->vm_file to
bo->base.filp, simliar to msm_gem_mmap_obj(), probably best done in
drm_gem_ttm_mmap().

cheers,
  Gerd
Daniel Vetter Nov. 12, 2019, 2:44 p.m. UTC | #11
On Tue, Nov 12, 2019 at 11:38:19AM +0100, Gerd Hoffmann wrote:
> On Tue, Nov 12, 2019 at 10:49:21AM +0100, Thomas Zimmermann wrote:
> > Hi
> > 
> > Am 12.11.19 um 10:32 schrieb Daniel Vetter:
> > > On Tue, Nov 12, 2019 at 10:26:44AM +0100, Thomas Zimmermann wrote:
> > >> Hi
> > >>
> > >> Am 08.11.19 um 17:27 schrieb Daniel Vetter:
> > >>> On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > >>>> On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > >>>>> Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > >>>>> introduced a GEM object mmap() hook which is expected to subtract the
> > >>>>> fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > >>>>> a fake offset.
> > >>>>>
> > >>>>> To fix this, let's always call mmap() object callback with an offset of 0,
> > >>>>> and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > >>>>>
> > >>>>> TTM still needs the fake offset, so we have to add it back until that's
> > >>>>> fixed.
> > >>>>>
> > >>>>> Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > >>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
> > >>>>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > >>>>> Signed-off-by: Rob Herring <robh@kernel.org>
> > >>>>> ---
> > >>>>> v2:
> > >>>>> - Move subtracting the fake offset out of mmap() obj callbacks.
> > >>>>>
> > >>>>> I've tested shmem, but not ttm. Hopefully, I understood what's needed 
> > >>>>> for TTM.
> > >>>
> > >>> So unfortunately I'm already having regrets on this. We might even have
> > >>> broken some of the ttm drivers here.
> > >>>
> > >>> Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > >>> getting moved or whatever), then we do that with unmap_mapping_range.
> > >>> Which means each bo needs to be mapping with a unique (offset,
> > >>> adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > >>> this. We've also had this broken this for a while for the simplistic
> > >>> dma-buf mmap, since without any further action we'll reuse the address
> > >>> space of the dma-buf inode, not of the drm_device.
> > >>>
> > >>> Strangely both etnaviv and msm have a comment to that effect - grep for
> > >>> unmap_mapping_range. But neither actually uses it.
> > >>>
> > >>> Not exactly sure what's the best course of action here now.
> > >>>
> > >>> Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> > >>
> > >> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
> > >> These changes should be transparent.
> > > 
> > > There's still the issue that for dma-buf mmap vs drm mmap you use
> > > different f_mapping, which means ttm's pte shootdown won't work correctly
> > > for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
> > > be fine.
> > 
> > VRAM helpers don't support dmabufs.
> 
> It's not that simple.  Even when not supporting dma-buf export and
> import it is still possible to create dma-bufs, import them into the
> same driver (which doesn't actually export+import but just grabs a gem
> object reference instead) and also to mmap them via prime/dma-buf code
> path ...
> 
> Can ttm use the same trick msm uses?  Now that ttm bo's are a gem object
> superclass I think we should be able to switch vma->vm_file to
> bo->base.filp, simliar to msm_gem_mmap_obj(), probably best done in
> drm_gem_ttm_mmap().

bo->base.filp is the shmem inode file, and I'm not too sure how much shmem
approves of us misappropriating the mapping. For shmem only objects it
probably doesn't matter (since both gem mmaps and shmem mmaps will point
at the same underlying struct page), but for vram/ttm/anything else the
gem mmap might point into iomem, and shmem then might go boom trying to do
stuff with that. I think having our own mapping would be the cleanest
long-term approach ...
-Daniel
Rob Herring Nov. 12, 2019, 3:37 p.m. UTC | #12
On Tue, Nov 12, 2019 at 3:35 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Tue, Nov 12, 2019 at 09:52:54AM +0100, Gerd Hoffmann wrote:
> > On Fri, Nov 08, 2019 at 05:55:28PM +0100, Daniel Vetter wrote:
> > > On Fri, Nov 08, 2019 at 05:27:59PM +0100, Daniel Vetter wrote:
> > > > On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > > > > On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > > > > > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > introduced a GEM object mmap() hook which is expected to subtract the
> > > > > > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > > > > > a fake offset.
> > > > > >
> > > > > > To fix this, let's always call mmap() object callback with an offset of 0,
> > > > > > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > > > > >
> > > > > > TTM still needs the fake offset, so we have to add it back until that's
> > > > > > fixed.
> > > > > >
> > > > > > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > > > > ---
> > > > > > v2:
> > > > > > - Move subtracting the fake offset out of mmap() obj callbacks.
> > > > > >
> > > > > > I've tested shmem, but not ttm. Hopefully, I understood what's needed
> > > > > > for TTM.
> > > >
> > > > So unfortunately I'm already having regrets on this. We might even have
> > > > broken some of the ttm drivers here.
> > > >
> > > > Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > > > getting moved or whatever), then we do that with unmap_mapping_range.
> > > > Which means each bo needs to be mapping with a unique (offset,
> > > > adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > > > this. We've also had this broken this for a while for the simplistic
> > > > dma-buf mmap, since without any further action we'll reuse the address
> > > > space of the dma-buf inode, not of the drm_device.
> > > >
> > > > Strangely both etnaviv and msm have a comment to that effect - grep for
> > > > unmap_mapping_range. But neither actually uses it.
> > > >
> > > > Not exactly sure what's the best course of action here now.
> > > >
> > > > Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> > >
> > > Correction, I missed the unmap_mapping_range in the vma node manager
> > > header, so didn't spot the drivers using drm_vma_node_unmap. We did break
> > > all the ttm stuff :-/
> >
> > ttm still uses the offset, now added in ttm_bo_mmap_obj().  So, for
> > normal mmap behavior did not change I think.  The simplistic dma-buf
> > mmap did change, it now uses the offset because it goes through
> > ttm_bo_mmap_obj() too.
> >
> > Not fully sure which address space is used for dma-bufs though.  As far
> > I can see neither the old nor the new dma-buf mmap code path touch
> > vma->vm_file (unless the driver does explicitly care, like msm does in
> > msm_gem_mmap_obj).
> >
> > > Plus panfrost, which is using drm_gem_shmem_purge_locked.
> >
> > Hmm, looking at drm_gem_shmem_purge_locked I'm wondering why it uses a
> > mix of dev->anon_inode->i_mapping and file_inode(obj->filp)->i_mapping.

Probably my copy-n-paste from other implementations...

> > Also shmem helpers used a zero vm_pgoff before, only difference is the
> > change is applied in drm_gem_mmap_obj() now instead of somewhere in the
> > shmem helper code.
> >
> > slightly confused,

Me too.

> I think summary is:
> - shmem helper pte shotdown is broken for all cases now with
>   obj->funcs->mmap

Does it help that userspace always does a munmap before making pages purgeable?

> - ttm/vram-helpers only for dma-buf mmap redirection (because of the wrong
>   f/i_mapping).
>
> Rob, are you looking into this?

Still trying to understand all this...

> I guess there's two options:
> - Go back to fake offset everywhere, and weep.
> - Add a per-bo mapping struct, consistently use that everywhere (probably
>   more work).
>
> If we go with weeping maybe note the 2nd option as a todo item in
> todo.rst?
> -Daniel
>
> >   Gerd
> >
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
Daniel Vetter Nov. 12, 2019, 7:06 p.m. UTC | #13
On Tue, Nov 12, 2019 at 09:37:45AM -0600, Rob Herring wrote:
> On Tue, Nov 12, 2019 at 3:35 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Tue, Nov 12, 2019 at 09:52:54AM +0100, Gerd Hoffmann wrote:
> > > On Fri, Nov 08, 2019 at 05:55:28PM +0100, Daniel Vetter wrote:
> > > > On Fri, Nov 08, 2019 at 05:27:59PM +0100, Daniel Vetter wrote:
> > > > > On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > > > > > On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > > > > > > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > > introduced a GEM object mmap() hook which is expected to subtract the
> > > > > > > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > > > > > > a fake offset.
> > > > > > >
> > > > > > > To fix this, let's always call mmap() object callback with an offset of 0,
> > > > > > > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > > > > > >
> > > > > > > TTM still needs the fake offset, so we have to add it back until that's
> > > > > > > fixed.
> > > > > > >
> > > > > > > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > > > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > > > > > ---
> > > > > > > v2:
> > > > > > > - Move subtracting the fake offset out of mmap() obj callbacks.
> > > > > > >
> > > > > > > I've tested shmem, but not ttm. Hopefully, I understood what's needed
> > > > > > > for TTM.
> > > > >
> > > > > So unfortunately I'm already having regrets on this. We might even have
> > > > > broken some of the ttm drivers here.
> > > > >
> > > > > Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > > > > getting moved or whatever), then we do that with unmap_mapping_range.
> > > > > Which means each bo needs to be mapping with a unique (offset,
> > > > > adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > > > > this. We've also had this broken this for a while for the simplistic
> > > > > dma-buf mmap, since without any further action we'll reuse the address
> > > > > space of the dma-buf inode, not of the drm_device.
> > > > >
> > > > > Strangely both etnaviv and msm have a comment to that effect - grep for
> > > > > unmap_mapping_range. But neither actually uses it.
> > > > >
> > > > > Not exactly sure what's the best course of action here now.
> > > > >
> > > > > Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> > > >
> > > > Correction, I missed the unmap_mapping_range in the vma node manager
> > > > header, so didn't spot the drivers using drm_vma_node_unmap. We did break
> > > > all the ttm stuff :-/
> > >
> > > ttm still uses the offset, now added in ttm_bo_mmap_obj().  So, for
> > > normal mmap behavior did not change I think.  The simplistic dma-buf
> > > mmap did change, it now uses the offset because it goes through
> > > ttm_bo_mmap_obj() too.
> > >
> > > Not fully sure which address space is used for dma-bufs though.  As far
> > > I can see neither the old nor the new dma-buf mmap code path touch
> > > vma->vm_file (unless the driver does explicitly care, like msm does in
> > > msm_gem_mmap_obj).
> > >
> > > > Plus panfrost, which is using drm_gem_shmem_purge_locked.
> > >
> > > Hmm, looking at drm_gem_shmem_purge_locked I'm wondering why it uses a
> > > mix of dev->anon_inode->i_mapping and file_inode(obj->filp)->i_mapping.
> 
> Probably my copy-n-paste from other implementations...
> 
> > > Also shmem helpers used a zero vm_pgoff before, only difference is the
> > > change is applied in drm_gem_mmap_obj() now instead of somewhere in the
> > > shmem helper code.
> > >
> > > slightly confused,
> 
> Me too.
> 
> > I think summary is:
> > - shmem helper pte shotdown is broken for all cases now with
> >   obj->funcs->mmap
> 
> Does it help that userspace always does a munmap before making pages purgeable?

I guess ... but kinda awkward to leave this issue in here, it's really
surprising if you call the pte shootdown function, and it doesn't work as
advertised.
-Daniel

> 
> > - ttm/vram-helpers only for dma-buf mmap redirection (because of the wrong
> >   f/i_mapping).
> >
> > Rob, are you looking into this?
> 
> Still trying to understand all this...
> 
> > I guess there's two options:
> > - Go back to fake offset everywhere, and weep.
> > - Add a per-bo mapping struct, consistently use that everywhere (probably
> >   more work).
> >
> > If we go with weeping maybe note the 2nd option as a todo item in
> > todo.rst?
> > -Daniel
> >
> > >   Gerd
> > >
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
Rob Herring Nov. 12, 2019, 9:31 p.m. UTC | #14
On Tue, Nov 12, 2019 at 1:06 PM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Tue, Nov 12, 2019 at 09:37:45AM -0600, Rob Herring wrote:
> > On Tue, Nov 12, 2019 at 3:35 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> > >
> > > On Tue, Nov 12, 2019 at 09:52:54AM +0100, Gerd Hoffmann wrote:
> > > > On Fri, Nov 08, 2019 at 05:55:28PM +0100, Daniel Vetter wrote:
> > > > > On Fri, Nov 08, 2019 at 05:27:59PM +0100, Daniel Vetter wrote:
> > > > > > On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > > > > > > On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > > > > > > > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > > > introduced a GEM object mmap() hook which is expected to subtract the
> > > > > > > > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > > > > > > > a fake offset.
> > > > > > > >
> > > > > > > > To fix this, let's always call mmap() object callback with an offset of 0,
> > > > > > > > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > > > > > > >
> > > > > > > > TTM still needs the fake offset, so we have to add it back until that's
> > > > > > > > fixed.
> > > > > > > >
> > > > > > > > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > > > > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > > > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > > > > > > ---
> > > > > > > > v2:
> > > > > > > > - Move subtracting the fake offset out of mmap() obj callbacks.
> > > > > > > >
> > > > > > > > I've tested shmem, but not ttm. Hopefully, I understood what's needed
> > > > > > > > for TTM.
> > > > > >
> > > > > > So unfortunately I'm already having regrets on this. We might even have
> > > > > > broken some of the ttm drivers here.
> > > > > >
> > > > > > Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > > > > > getting moved or whatever), then we do that with unmap_mapping_range.
> > > > > > Which means each bo needs to be mapping with a unique (offset,
> > > > > > adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > > > > > this. We've also had this broken this for a while for the simplistic
> > > > > > dma-buf mmap, since without any further action we'll reuse the address
> > > > > > space of the dma-buf inode, not of the drm_device.
> > > > > >
> > > > > > Strangely both etnaviv and msm have a comment to that effect - grep for
> > > > > > unmap_mapping_range. But neither actually uses it.
> > > > > >
> > > > > > Not exactly sure what's the best course of action here now.
> > > > > >
> > > > > > Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> > > > >
> > > > > Correction, I missed the unmap_mapping_range in the vma node manager
> > > > > header, so didn't spot the drivers using drm_vma_node_unmap. We did break
> > > > > all the ttm stuff :-/
> > > >
> > > > ttm still uses the offset, now added in ttm_bo_mmap_obj().  So, for
> > > > normal mmap behavior did not change I think.  The simplistic dma-buf
> > > > mmap did change, it now uses the offset because it goes through
> > > > ttm_bo_mmap_obj() too.
> > > >
> > > > Not fully sure which address space is used for dma-bufs though.  As far
> > > > I can see neither the old nor the new dma-buf mmap code path touch
> > > > vma->vm_file (unless the driver does explicitly care, like msm does in
> > > > msm_gem_mmap_obj).
> > > >
> > > > > Plus panfrost, which is using drm_gem_shmem_purge_locked.
> > > >
> > > > Hmm, looking at drm_gem_shmem_purge_locked I'm wondering why it uses a
> > > > mix of dev->anon_inode->i_mapping and file_inode(obj->filp)->i_mapping.
> >
> > Probably my copy-n-paste from other implementations...

I checked and yes, this is just copy-n-paste from msm. BTW, the code
with the unmap_mapping_range comment mentioned above doesn't apply for
shmem helpers because it applies to cacheable mappings which are (yet)
supported.

> >
> > > > Also shmem helpers used a zero vm_pgoff before, only difference is the
> > > > change is applied in drm_gem_mmap_obj() now instead of somewhere in the
> > > > shmem helper code.
> > > >
> > > > slightly confused,
> >
> > Me too.
> >
> > > I think summary is:
> > > - shmem helper pte shotdown is broken for all cases now with
> > >   obj->funcs->mmap
> >
> > Does it help that userspace always does a munmap before making pages purgeable?
>
> I guess ... but kinda awkward to leave this issue in here, it's really
> surprising if you call the pte shootdown function, and it doesn't work as
> advertised.

I was mainly wondering how this worked for us and how to hit it not
working to test fixing it.

Is there a simple way to check if a BO is mmapped or not? I'd assume
so, just don't know the answer off hand. A simple fix would be to
either require buffer is not mapped before madvise or skip purging if
it is mapped.

Rob
Daniel Vetter Nov. 12, 2019, 10:14 p.m. UTC | #15
On Tue, Nov 12, 2019 at 10:31 PM Rob Herring <robh@kernel.org> wrote:
>
> On Tue, Nov 12, 2019 at 1:06 PM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Tue, Nov 12, 2019 at 09:37:45AM -0600, Rob Herring wrote:
> > > On Tue, Nov 12, 2019 at 3:35 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> > > >
> > > > On Tue, Nov 12, 2019 at 09:52:54AM +0100, Gerd Hoffmann wrote:
> > > > > On Fri, Nov 08, 2019 at 05:55:28PM +0100, Daniel Vetter wrote:
> > > > > > On Fri, Nov 08, 2019 at 05:27:59PM +0100, Daniel Vetter wrote:
> > > > > > > On Fri, Oct 25, 2019 at 09:30:42AM +0200, Daniel Vetter wrote:
> > > > > > > > On Thu, Oct 24, 2019 at 02:18:59PM -0500, Rob Herring wrote:
> > > > > > > > > Commit c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > > > > introduced a GEM object mmap() hook which is expected to subtract the
> > > > > > > > > fake offset from vm_pgoff. However, for mmap() on dmabufs, there is not
> > > > > > > > > a fake offset.
> > > > > > > > >
> > > > > > > > > To fix this, let's always call mmap() object callback with an offset of 0,
> > > > > > > > > and leave it up to drm_gem_mmap_obj() to remove the fake offset.
> > > > > > > > >
> > > > > > > > > TTM still needs the fake offset, so we have to add it back until that's
> > > > > > > > > fixed.
> > > > > > > > >
> > > > > > > > > Fixes: c40069cb7bd6 ("drm: add mmap() to drm_gem_object_funcs")
> > > > > > > > > Cc: Gerd Hoffmann <kraxel@redhat.com>
> > > > > > > > > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > > > > > Signed-off-by: Rob Herring <robh@kernel.org>
> > > > > > > > > ---
> > > > > > > > > v2:
> > > > > > > > > - Move subtracting the fake offset out of mmap() obj callbacks.
> > > > > > > > >
> > > > > > > > > I've tested shmem, but not ttm. Hopefully, I understood what's needed
> > > > > > > > > for TTM.
> > > > > > >
> > > > > > > So unfortunately I'm already having regrets on this. We might even have
> > > > > > > broken some of the ttm drivers here.
> > > > > > >
> > > > > > > Trouble is, if you need to shoot down userspace ptes of a bo (because it's
> > > > > > > getting moved or whatever), then we do that with unmap_mapping_range.
> > > > > > > Which means each bo needs to be mapping with a unique (offset,
> > > > > > > adress_space), or it won't work. By remapping all the bo to 0 we've broken
> > > > > > > this. We've also had this broken this for a while for the simplistic
> > > > > > > dma-buf mmap, since without any further action we'll reuse the address
> > > > > > > space of the dma-buf inode, not of the drm_device.
> > > > > > >
> > > > > > > Strangely both etnaviv and msm have a comment to that effect - grep for
> > > > > > > unmap_mapping_range. But neither actually uses it.
> > > > > > >
> > > > > > > Not exactly sure what's the best course of action here now.
> > > > > > >
> > > > > > > Also adding Thomas Zimmermann, who's worked on all the vram helpers.
> > > > > >
> > > > > > Correction, I missed the unmap_mapping_range in the vma node manager
> > > > > > header, so didn't spot the drivers using drm_vma_node_unmap. We did break
> > > > > > all the ttm stuff :-/
> > > > >
> > > > > ttm still uses the offset, now added in ttm_bo_mmap_obj().  So, for
> > > > > normal mmap behavior did not change I think.  The simplistic dma-buf
> > > > > mmap did change, it now uses the offset because it goes through
> > > > > ttm_bo_mmap_obj() too.
> > > > >
> > > > > Not fully sure which address space is used for dma-bufs though.  As far
> > > > > I can see neither the old nor the new dma-buf mmap code path touch
> > > > > vma->vm_file (unless the driver does explicitly care, like msm does in
> > > > > msm_gem_mmap_obj).
> > > > >
> > > > > > Plus panfrost, which is using drm_gem_shmem_purge_locked.
> > > > >
> > > > > Hmm, looking at drm_gem_shmem_purge_locked I'm wondering why it uses a
> > > > > mix of dev->anon_inode->i_mapping and file_inode(obj->filp)->i_mapping.
> > >
> > > Probably my copy-n-paste from other implementations...
>
> I checked and yes, this is just copy-n-paste from msm. BTW, the code
> with the unmap_mapping_range comment mentioned above doesn't apply for
> shmem helpers because it applies to cacheable mappings which are (yet)
> supported.
>
> > >
> > > > > Also shmem helpers used a zero vm_pgoff before, only difference is the
> > > > > change is applied in drm_gem_mmap_obj() now instead of somewhere in the
> > > > > shmem helper code.
> > > > >
> > > > > slightly confused,
> > >
> > > Me too.
> > >
> > > > I think summary is:
> > > > - shmem helper pte shotdown is broken for all cases now with
> > > >   obj->funcs->mmap
> > >
> > > Does it help that userspace always does a munmap before making pages purgeable?
> >
> > I guess ... but kinda awkward to leave this issue in here, it's really
> > surprising if you call the pte shootdown function, and it doesn't work as
> > advertised.
>
> I was mainly wondering how this worked for us and how to hit it not
> working to test fixing it.
>
> Is there a simple way to check if a BO is mmapped or not? I'd assume
> so, just don't know the answer off hand. A simple fix would be to
> either require buffer is not mapped before madvise or skip purging if
> it is mapped.

Imo simplest fix is to just go back and readd the fake offset. Ugly,
but works at least. That leaves exported dma-bufs, and maybe those
shouldn't be quite so funny in their behaviour (or we just exchange
the mapping in the vma, should be a one-liner to address that).
Workarounds and hacks in drivers definitely sounds like the wrong
approach here to me.
-Daniel
Gerd Hoffmann Nov. 13, 2019, 7:39 a.m. UTC | #16
Hi,

> > > >> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
> > > >> These changes should be transparent.
> > > > 
> > > > There's still the issue that for dma-buf mmap vs drm mmap you use
> > > > different f_mapping, which means ttm's pte shootdown won't work correctly
> > > > for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
> > > > be fine.
> > > 
> > > VRAM helpers don't support dmabufs.
> > 
> > It's not that simple.  Even when not supporting dma-buf export and
> > import it is still possible to create dma-bufs, import them into the
> > same driver (which doesn't actually export+import but just grabs a gem
> > object reference instead) and also to mmap them via prime/dma-buf code
> > path ...

... but after looking again I think we are all green here.  Given that
only self-import works we'll only see vram gem objects in the mmap code
path, which should have everything set up correctly.  Same goes for qxl.

All other ttm drivers still use the old mmap code path, so all green
there too I think.  Also I somehow doubt dma-buf mmap vs. drm mmap ends
up using different f_mapping, ttm code has a WARN_ON in ttm_bo_vm_open()
which would fire should that be the case.

Do imported dma-bufs hit the drm mmap code path in the first place?
Wouldn't mmap be handled by the exporting driver?

> > Can ttm use the same trick msm uses?  Now that ttm bo's are a gem object
> > superclass I think we should be able to switch vma->vm_file to
> > bo->base.filp, simliar to msm_gem_mmap_obj(), probably best done in
> > drm_gem_ttm_mmap().
> 
> bo->base.filp is the shmem inode file, and I'm not too sure how much shmem
> approves of us misappropriating the mapping. For shmem only objects it
> probably doesn't matter (since both gem mmaps and shmem mmaps will point
> at the same underlying struct page), but for vram/ttm/anything else the
> gem mmap might point into iomem, and shmem then might go boom trying to do
> stuff with that.

Yes, agreeing here after wading through the code ...

> I think having our own mapping would be the cleanest
> long-term approach ...

You mean using per drm object (instead of per drm device) address spaces?

cheers,
  Gerd
Gerd Hoffmann Nov. 13, 2019, 7:53 a.m. UTC | #17
Hi,

> > > I guess ... but kinda awkward to leave this issue in here, it's really
> > > surprising if you call the pte shootdown function, and it doesn't work as
> > > advertised.
> >
> > I was mainly wondering how this worked for us and how to hit it not
> > working to test fixing it.
> >
> > Is there a simple way to check if a BO is mmapped or not? I'd assume
> > so, just don't know the answer off hand. A simple fix would be to
> > either require buffer is not mapped before madvise or skip purging if
> > it is mapped.
> 
> Imo simplest fix is to just go back and readd the fake offset. Ugly,
> but works at least.

Well, shmem helpers removed the fake offset before, so I'm likewise
starting to wonder what exactly broke by removing the offset elsewhere.

Maybe shmem helpers where already broken before that patch.  I can see
that removing the fake offset and continuing to use a shared address
space isn't going to fly.  Unlike ttm the shmem helpers should have no
problems using obj->filp, but I can't see the shmem helper code
switching vma->vm_file over to obj->filp anywhere ...

cheers,
  Gerd
Daniel Vetter Nov. 13, 2019, 8:17 a.m. UTC | #18
On Wed, Nov 13, 2019 at 8:39 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
>   Hi,
>
> > > > >> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
> > > > >> These changes should be transparent.
> > > > >
> > > > > There's still the issue that for dma-buf mmap vs drm mmap you use
> > > > > different f_mapping, which means ttm's pte shootdown won't work correctly
> > > > > for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
> > > > > be fine.
> > > >
> > > > VRAM helpers don't support dmabufs.
> > >
> > > It's not that simple.  Even when not supporting dma-buf export and
> > > import it is still possible to create dma-bufs, import them into the
> > > same driver (which doesn't actually export+import but just grabs a gem
> > > object reference instead) and also to mmap them via prime/dma-buf code
> > > path ...
>
> ... but after looking again I think we are all green here.  Given that
> only self-import works we'll only see vram gem objects in the mmap code
> path, which should have everything set up correctly.  Same goes for qxl.
>
> All other ttm drivers still use the old mmap code path, so all green
> there too I think.  Also I somehow doubt dma-buf mmap vs. drm mmap ends
> up using different f_mapping, ttm code has a WARN_ON in ttm_bo_vm_open()
> which would fire should that be the case.
>
> Do imported dma-bufs hit the drm mmap code path in the first place?
> Wouldn't mmap be handled by the exporting driver?

drm_gem_dmabuf_mmap -> obj->funcs->mmap -> ttm_bo_mmap_obj

And I'm not seeing anyone adjusting vm_file->f_mapping anywhere here at all.

Note to hit this you need userspace to
- handle2fd on a buffer to create a dma-buf fd
- call mmap directly on that dma-buf fd

> > > Can ttm use the same trick msm uses?  Now that ttm bo's are a gem object
> > > superclass I think we should be able to switch vma->vm_file to
> > > bo->base.filp, simliar to msm_gem_mmap_obj(), probably best done in
> > > drm_gem_ttm_mmap().
> >
> > bo->base.filp is the shmem inode file, and I'm not too sure how much shmem
> > approves of us misappropriating the mapping. For shmem only objects it
> > probably doesn't matter (since both gem mmaps and shmem mmaps will point
> > at the same underlying struct page), but for vram/ttm/anything else the
> > gem mmap might point into iomem, and shmem then might go boom trying to do
> > stuff with that.
>
> Yes, agreeing here after wading through the code ...
>
> > I think having our own mapping would be the cleanest
> > long-term approach ...
>
> You mean using per drm object (instead of per drm device) address spaces?

Yup. But I think that would be quite a pile of work, since we need an
anon inode for each gem bo.
-Daniel
Gerd Hoffmann Nov. 13, 2019, 1:51 p.m. UTC | #19
Hi,

> > ... but after looking again I think we are all green here.  Given that
> > only self-import works we'll only see vram gem objects in the mmap code
> > path, which should have everything set up correctly.  Same goes for qxl.
> >
> > All other ttm drivers still use the old mmap code path, so all green
> > there too I think.  Also I somehow doubt dma-buf mmap vs. drm mmap ends
> > up using different f_mapping, ttm code has a WARN_ON in ttm_bo_vm_open()
> > which would fire should that be the case.
> >
> > Do imported dma-bufs hit the drm mmap code path in the first place?
> > Wouldn't mmap be handled by the exporting driver?
> 
> drm_gem_dmabuf_mmap -> obj->funcs->mmap -> ttm_bo_mmap_obj
> 
> And I'm not seeing anyone adjusting vm_file->f_mapping anywhere here at all.

[ some more code browsing ]

Ok, I see.  dma-bufs get their own file, their own anon inode and
thereby their own address space.  So that it used when mmaping the
dma-buf.

drm filehandle's get the shared address space instead, drm_open() sets
it.

So, yes, I see the problem.  It's not new though, as far I can see the
old dma-buf mmap code path doesn't adjust f_mapping anywhere either ...

> Note to hit this you need userspace to
> - handle2fd on a buffer to create a dma-buf fd
> - call mmap directly on that dma-buf fd

Hmm, seems for handle2fd I need a dummy gem_prime_get_sg_table function
wired up even when not actually exporting/importing anything.  So I
think neither qxl nor any of the vram drivers allow to trigger that (and
no other ttm driver uses the new ttm mmap code yet).

So, $subject patch should not make things worse in ttm land.

When hacking the bochs driver to have export callbacks (without
supporting actual exports) handle2fd + mmap() callback works fine.
Didn't verify yet I actually get the correct pages mapped.  But maybe
mmap() isn't the problem when the correct address space is important for
unmap only.

Is there a good test case?

cheers,
  Gerd
Rob Herring Nov. 13, 2019, 1:53 p.m. UTC | #20
On Wed, Nov 13, 2019 at 2:18 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Wed, Nov 13, 2019 at 8:39 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
> >
> >   Hi,
> >
> > > > > >> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
> > > > > >> These changes should be transparent.
> > > > > >
> > > > > > There's still the issue that for dma-buf mmap vs drm mmap you use
> > > > > > different f_mapping, which means ttm's pte shootdown won't work correctly
> > > > > > for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
> > > > > > be fine.
> > > > >
> > > > > VRAM helpers don't support dmabufs.
> > > >
> > > > It's not that simple.  Even when not supporting dma-buf export and
> > > > import it is still possible to create dma-bufs, import them into the
> > > > same driver (which doesn't actually export+import but just grabs a gem
> > > > object reference instead) and also to mmap them via prime/dma-buf code
> > > > path ...
> >
> > ... but after looking again I think we are all green here.  Given that
> > only self-import works we'll only see vram gem objects in the mmap code
> > path, which should have everything set up correctly.  Same goes for qxl.
> >
> > All other ttm drivers still use the old mmap code path, so all green
> > there too I think.  Also I somehow doubt dma-buf mmap vs. drm mmap ends
> > up using different f_mapping, ttm code has a WARN_ON in ttm_bo_vm_open()
> > which would fire should that be the case.
> >
> > Do imported dma-bufs hit the drm mmap code path in the first place?
> > Wouldn't mmap be handled by the exporting driver?
>
> drm_gem_dmabuf_mmap -> obj->funcs->mmap -> ttm_bo_mmap_obj
>
> And I'm not seeing anyone adjusting vm_file->f_mapping anywhere here at all.
>
> Note to hit this you need userspace to
> - handle2fd on a buffer to create a dma-buf fd
> - call mmap directly on that dma-buf fd

That was exactly the vgem IGT test that prompted $subject fix. (With
vgem modified to use shmem helpers)

Rob
Daniel Vetter Nov. 13, 2019, 4:27 p.m. UTC | #21
On Wed, Nov 13, 2019 at 02:51:45PM +0100, Gerd Hoffmann wrote:
>   Hi,
> 
> > > ... but after looking again I think we are all green here.  Given that
> > > only self-import works we'll only see vram gem objects in the mmap code
> > > path, which should have everything set up correctly.  Same goes for qxl.
> > >
> > > All other ttm drivers still use the old mmap code path, so all green
> > > there too I think.  Also I somehow doubt dma-buf mmap vs. drm mmap ends
> > > up using different f_mapping, ttm code has a WARN_ON in ttm_bo_vm_open()
> > > which would fire should that be the case.
> > >
> > > Do imported dma-bufs hit the drm mmap code path in the first place?
> > > Wouldn't mmap be handled by the exporting driver?
> > 
> > drm_gem_dmabuf_mmap -> obj->funcs->mmap -> ttm_bo_mmap_obj
> > 
> > And I'm not seeing anyone adjusting vm_file->f_mapping anywhere here at all.
> 
> [ some more code browsing ]
> 
> Ok, I see.  dma-bufs get their own file, their own anon inode and
> thereby their own address space.  So that it used when mmaping the
> dma-buf.
> 
> drm filehandle's get the shared address space instead, drm_open() sets
> it.
> 
> So, yes, I see the problem.  It's not new though, as far I can see the
> old dma-buf mmap code path doesn't adjust f_mapping anywhere either ...
> 
> > Note to hit this you need userspace to
> > - handle2fd on a buffer to create a dma-buf fd
> > - call mmap directly on that dma-buf fd
> 
> Hmm, seems for handle2fd I need a dummy gem_prime_get_sg_table function
> wired up even when not actually exporting/importing anything.  So I
> think neither qxl nor any of the vram drivers allow to trigger that (and
> no other ttm driver uses the new ttm mmap code yet).
> 
> So, $subject patch should not make things worse in ttm land.
> 
> When hacking the bochs driver to have export callbacks (without
> supporting actual exports) handle2fd + mmap() callback works fine.
> Didn't verify yet I actually get the correct pages mapped.  But maybe
> mmap() isn't the problem when the correct address space is important for
> unmap only.
> 
> Is there a good test case?

You need memory pressure, to force ttm to unmap the bo, not userspace. So
roughly
1. create bo
2. mmap it through drm fd, write some stuff
3. export to dma-buf, mmap it, verify stuff is there
4. create a pile more bo, mmap them write to them
5. once you've thrashed all of vram enough, recheck your original bo. If
I'm right you should get the following:
   - drm fd mmap still show right content
   - dma-buf fd mmap shows random crap that you've written into other
     buffers

Ofc you need to make sure that an mmap actually forces the buffer into
vram. So might need a combo of modeset+mmap, to make that happen. Plain
mmap might just give you ptes that point into system memory, which is not
managed by ttm like vram.

munmap called by userspace isn't a problem, since that starts from the
right struct mm_struct. It's when you start with the object (i.e. in the
driver), and need to figure out where all the various vma that mmap it are
where this matters.
-Daniel
Daniel Vetter Nov. 13, 2019, 4:28 p.m. UTC | #22
On Wed, Nov 13, 2019 at 07:53:56AM -0600, Rob Herring wrote:
> On Wed, Nov 13, 2019 at 2:18 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Wed, Nov 13, 2019 at 8:39 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
> > >
> > >   Hi,
> > >
> > > > > > >> VRAM helpers use drm_gem_ttm_mmap(), which wraps ttm_bo_mmap_obj().
> > > > > > >> These changes should be transparent.
> > > > > > >
> > > > > > > There's still the issue that for dma-buf mmap vs drm mmap you use
> > > > > > > different f_mapping, which means ttm's pte shootdown won't work correctly
> > > > > > > for dma-buf mmaps. But yeah normal operation for ttm/vram helpers should
> > > > > > > be fine.
> > > > > >
> > > > > > VRAM helpers don't support dmabufs.
> > > > >
> > > > > It's not that simple.  Even when not supporting dma-buf export and
> > > > > import it is still possible to create dma-bufs, import them into the
> > > > > same driver (which doesn't actually export+import but just grabs a gem
> > > > > object reference instead) and also to mmap them via prime/dma-buf code
> > > > > path ...
> > >
> > > ... but after looking again I think we are all green here.  Given that
> > > only self-import works we'll only see vram gem objects in the mmap code
> > > path, which should have everything set up correctly.  Same goes for qxl.
> > >
> > > All other ttm drivers still use the old mmap code path, so all green
> > > there too I think.  Also I somehow doubt dma-buf mmap vs. drm mmap ends
> > > up using different f_mapping, ttm code has a WARN_ON in ttm_bo_vm_open()
> > > which would fire should that be the case.
> > >
> > > Do imported dma-bufs hit the drm mmap code path in the first place?
> > > Wouldn't mmap be handled by the exporting driver?
> >
> > drm_gem_dmabuf_mmap -> obj->funcs->mmap -> ttm_bo_mmap_obj
> >
> > And I'm not seeing anyone adjusting vm_file->f_mapping anywhere here at all.
> >
> > Note to hit this you need userspace to
> > - handle2fd on a buffer to create a dma-buf fd
> > - call mmap directly on that dma-buf fd
> 
> That was exactly the vgem IGT test that prompted $subject fix. (With
> vgem modified to use shmem helpers)

See my other mail, this only hits the right mmap paths. For the unmap side
you need even more (and that part is driver dependent, and vgem would need
some debug tricks to expose that for testing).
-Daniel
Gerd Hoffmann Nov. 15, 2019, 9:37 a.m. UTC | #23
> You need memory pressure, to force ttm to unmap the bo, not userspace. So
> roughly
> 1. create bo
> 2. mmap it through drm fd, write some stuff
> 3. export to dma-buf, mmap it, verify stuff is there
> 4. create a pile more bo, mmap them write to them
> 5. once you've thrashed all of vram enough, recheck your original bo. If
> I'm right you should get the following:
>    - drm fd mmap still show right content
>    - dma-buf fd mmap shows random crap that you've written into other
>      buffers
> 
> Ofc you need to make sure that an mmap actually forces the buffer into
> vram. So might need a combo of modeset+mmap, to make that happen. Plain
> mmap might just give you ptes that point into system memory, which is not
> managed by ttm like vram.

Is any move buffer good enough to trigger this, i.e. will SYSTEM -> VRAM
work too?  That'll be easier because all I need to do is map the buffer
to a crtc to force pinning to vram, then check if the mappings are
intact still ...

cheers,
  Gerd
Daniel Vetter Nov. 15, 2019, 10:18 a.m. UTC | #24
On Fri, Nov 15, 2019 at 10:37 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
> > You need memory pressure, to force ttm to unmap the bo, not userspace. So
> > roughly
> > 1. create bo
> > 2. mmap it through drm fd, write some stuff
> > 3. export to dma-buf, mmap it, verify stuff is there
> > 4. create a pile more bo, mmap them write to them
> > 5. once you've thrashed all of vram enough, recheck your original bo. If
> > I'm right you should get the following:
> >    - drm fd mmap still show right content
> >    - dma-buf fd mmap shows random crap that you've written into other
> >      buffers
> >
> > Ofc you need to make sure that an mmap actually forces the buffer into
> > vram. So might need a combo of modeset+mmap, to make that happen. Plain
> > mmap might just give you ptes that point into system memory, which is not
> > managed by ttm like vram.
>
> Is any move buffer good enough to trigger this, i.e. will SYSTEM -> VRAM
> work too?  That'll be easier because all I need to do is map the buffer
> to a crtc to force pinning to vram, then check if the mappings are
> intact still ...

I think that should work too. Just make sure you actually write
through SYSTEM first (maybe with some printk or whatever).
-Daniel
Gerd Hoffmann Nov. 15, 2019, 10:56 a.m. UTC | #25
On Fri, Nov 15, 2019 at 11:18:28AM +0100, Daniel Vetter wrote:
> On Fri, Nov 15, 2019 at 10:37 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
> >
> > > You need memory pressure, to force ttm to unmap the bo, not userspace. So
> > > roughly
> > > 1. create bo
> > > 2. mmap it through drm fd, write some stuff
> > > 3. export to dma-buf, mmap it, verify stuff is there
> > > 4. create a pile more bo, mmap them write to them
> > > 5. once you've thrashed all of vram enough, recheck your original bo. If
> > > I'm right you should get the following:
> > >    - drm fd mmap still show right content
> > >    - dma-buf fd mmap shows random crap that you've written into other
> > >      buffers
> > >
> > > Ofc you need to make sure that an mmap actually forces the buffer into
> > > vram. So might need a combo of modeset+mmap, to make that happen. Plain
> > > mmap might just give you ptes that point into system memory, which is not
> > > managed by ttm like vram.
> >
> > Is any move buffer good enough to trigger this, i.e. will SYSTEM -> VRAM
> > work too?  That'll be easier because all I need to do is map the buffer
> > to a crtc to force pinning to vram, then check if the mappings are
> > intact still ...
> 
> I think that should work too.

Seems to work ok for ttm/vram.

Test code:
  https://git.kraxel.org/cgit/drminfo/commit/?id=a9eb96504dc17376e07b5c6edf5296b41a48bbfe

> Just make sure you actually write
> through SYSTEM first (maybe with some printk or whatever).

That works fine.  Sprinkled ...

	system("cat /sys/kernel/debug/dri/0/vram-mm"); 

... into the test code, and drmModeSetCrtc() indeed makes the gem object show
up there.

cheers,
  Gerd
Daniel Vetter Nov. 15, 2019, 3:31 p.m. UTC | #26
On Fri, Nov 15, 2019 at 11:56 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
> On Fri, Nov 15, 2019 at 11:18:28AM +0100, Daniel Vetter wrote:
> > On Fri, Nov 15, 2019 at 10:37 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
> > >
> > > > You need memory pressure, to force ttm to unmap the bo, not userspace. So
> > > > roughly
> > > > 1. create bo
> > > > 2. mmap it through drm fd, write some stuff
> > > > 3. export to dma-buf, mmap it, verify stuff is there
> > > > 4. create a pile more bo, mmap them write to them
> > > > 5. once you've thrashed all of vram enough, recheck your original bo. If
> > > > I'm right you should get the following:
> > > >    - drm fd mmap still show right content
> > > >    - dma-buf fd mmap shows random crap that you've written into other
> > > >      buffers
> > > >
> > > > Ofc you need to make sure that an mmap actually forces the buffer into
> > > > vram. So might need a combo of modeset+mmap, to make that happen. Plain
> > > > mmap might just give you ptes that point into system memory, which is not
> > > > managed by ttm like vram.
> > >
> > > Is any move buffer good enough to trigger this, i.e. will SYSTEM -> VRAM
> > > work too?  That'll be easier because all I need to do is map the buffer
> > > to a crtc to force pinning to vram, then check if the mappings are
> > > intact still ...
> >
> > I think that should work too.
>
> Seems to work ok for ttm/vram.
>
> Test code:
>   https://git.kraxel.org/cgit/drminfo/commit/?id=a9eb96504dc17376e07b5c6edf5296b41a48bbfe

I think that's not nasty enough. If the mappings aren't updated, then
you'll still see the the same old pages with the right contents. You
need to change them somehow after they migrated (with vram eviction
that happens automatically since there'll b another object in the same
spot, for system memory I think you need the shrinker to kick in and
free the pages first). Easiest probably to wait for a key press so you
can appreciate the color, then write a different color (full screen)
when the buffer is in vram.

> > Just make sure you actually write
> > through SYSTEM first (maybe with some printk or whatever).
>
> That works fine.  Sprinkled ...
>
>         system("cat /sys/kernel/debug/dri/0/vram-mm");
>
> ... into the test code, and drmModeSetCrtc() indeed makes the gem object show
> up there.

You'd need to check the ptes themselves. Which I think not even proc
shows by default (only the file that's supposed to be mapped). But
good to confirm that the buffer moved at least.
-Daniel
Gerd Hoffmann Nov. 18, 2019, 10:40 a.m. UTC | #27
Hi,

> > > > Is any move buffer good enough to trigger this, i.e. will SYSTEM -> VRAM
> > > > work too?  That'll be easier because all I need to do is map the buffer
> > > > to a crtc to force pinning to vram, then check if the mappings are
> > > > intact still ...
> > >
> > > I think that should work too.
> >
> > Seems to work ok for ttm/vram.
> >
> > Test code:
> >   https://git.kraxel.org/cgit/drminfo/commit/?id=a9eb96504dc17376e07b5c6edf5296b41a48bbfe
> 
> I think that's not nasty enough. If the mappings aren't updated, then
> you'll still see the the same old pages with the right contents. You
> need to change them somehow after they migrated (with vram eviction
> that happens automatically since there'll b another object in the same
> spot, for system memory I think you need the shrinker to kick in and
> free the pages first). Easiest probably to wait for a key press so you
> can appreciate the color, then write a different color (full screen)
> when the buffer is in vram.

update-object-after-move works fine.

try zap mappings with madvise(dontneed) has no bad effects (after vram
move, trying to force re-creating the ptes).

didn't try the memory pressure thing yet.

> You'd need to check the ptes themselves. Which I think not even proc
> shows by default (only the file that's supposed to be mapped). But
> good to confirm that the buffer moved at least.

One reproducable glitch found:  fork() while having a dma-buf mapped
triggers the WARN_ON in ttm_bo_vm_open().  Both old & new mmap code
paths, so this isn't something new coming from the
drm_gem_object_funcs.mmap switch.  Instead it is an old issue coming
from the address space handling being different in drm mmap and dmabuf
mmap code paths.

I can see now why you want a private address space for each object.
Does that imply we need an anon_inode for each gem object?  Or is
there some more lightweight way to do this?

cheers,
  Gerd
Daniel Vetter Nov. 18, 2019, 4:49 p.m. UTC | #28
On Mon, Nov 18, 2019 at 11:40:26AM +0100, Gerd Hoffmann wrote:
>   Hi,
> 
> > > > > Is any move buffer good enough to trigger this, i.e. will SYSTEM -> VRAM
> > > > > work too?  That'll be easier because all I need to do is map the buffer
> > > > > to a crtc to force pinning to vram, then check if the mappings are
> > > > > intact still ...
> > > >
> > > > I think that should work too.
> > >
> > > Seems to work ok for ttm/vram.
> > >
> > > Test code:
> > >   https://git.kraxel.org/cgit/drminfo/commit/?id=a9eb96504dc17376e07b5c6edf5296b41a48bbfe
> > 
> > I think that's not nasty enough. If the mappings aren't updated, then
> > you'll still see the the same old pages with the right contents. You
> > need to change them somehow after they migrated (with vram eviction
> > that happens automatically since there'll b another object in the same
> > spot, for system memory I think you need the shrinker to kick in and
> > free the pages first). Easiest probably to wait for a key press so you
> > can appreciate the color, then write a different color (full screen)
> > when the buffer is in vram.
> 
> update-object-after-move works fine.
> 
> try zap mappings with madvise(dontneed) has no bad effects (after vram
> move, trying to force re-creating the ptes).

Well if it's broken the zapping wouldn't work :-)

> didn't try the memory pressure thing yet.

I'm surprised ... and I have no idea how/why it keeps working.

For my paranoia, can you instrument the ttm page fault handler, and double
check that we get new faults after the move, and set up new ptes for the
same old mapping, but now pointing at the new place in vram?

> > You'd need to check the ptes themselves. Which I think not even proc
> > shows by default (only the file that's supposed to be mapped). But
> > good to confirm that the buffer moved at least.
> 
> One reproducable glitch found:  fork() while having a dma-buf mapped
> triggers the WARN_ON in ttm_bo_vm_open().  Both old & new mmap code
> paths, so this isn't something new coming from the
> drm_gem_object_funcs.mmap switch.  Instead it is an old issue coming
> from the address space handling being different in drm mmap and dmabuf
> mmap code paths.
> 
> I can see now why you want a private address space for each object.
> Does that imply we need an anon_inode for each gem object?  Or is
> there some more lightweight way to do this?

I have no idea whether we can get a address_space struct without an inode
(and no disasters).
-Daniel
Gerd Hoffmann Nov. 20, 2019, 8:05 a.m. UTC | #29
Hi,

> > I can see now why you want a private address space for each object.
> > Does that imply we need an anon_inode for each gem object?  Or is
> > there some more lightweight way to do this?
> 
> I have no idea whether we can get a address_space struct without an inode
> (and no disasters).

Anything building on shmem helpers should be able to use
obj->filp->f_mapping, right?  So allocating an inode unconditionally
doesn't look like a good plan.

Guess I'll go look at ttm-local changes for starters and see how it
goes.

cheers,
  Gerd
Daniel Vetter Nov. 20, 2019, 10:39 a.m. UTC | #30
On Wed, Nov 20, 2019 at 09:05:32AM +0100, Gerd Hoffmann wrote:
>   Hi,
> 
> > > I can see now why you want a private address space for each object.
> > > Does that imply we need an anon_inode for each gem object?  Or is
> > > there some more lightweight way to do this?
> > 
> > I have no idea whether we can get a address_space struct without an inode
> > (and no disasters).
> 
> Anything building on shmem helpers should be able to use
> obj->filp->f_mapping, right?  So allocating an inode unconditionally
> doesn't look like a good plan.

Not sure the shmem helpers forward the mmap to the underlying shmem file,
so not sure this is the greatest way either.

> Guess I'll go look at ttm-local changes for starters and see how it
> goes.

I think for ttm just consistently using the one per-device mapping for
everything, with all the fake offsets, is probably the quickest route.
Maybe also for for shmem helpers.

I'm kinda leaning towards that we just restore the fake offset everywhere,
and document how it works. Until someone comes up with a really bright
idea.
-Daniel
Gerd Hoffmann Nov. 20, 2019, 11:40 a.m. UTC | #31
Hi,

> > Anything building on shmem helpers should be able to use
> > obj->filp->f_mapping, right?  So allocating an inode unconditionally
> > doesn't look like a good plan.
> 
> Not sure the shmem helpers forward the mmap to the underlying shmem file,
> so not sure this is the greatest way either.

I think so, shmem helpers already zap the fake offset, and this would
not work without per-object address space I think.

> > Guess I'll go look at ttm-local changes for starters and see how it
> > goes.
> 
> I think for ttm just consistently using the one per-device mapping for
> everything, with all the fake offsets, is probably the quickest route.

Hmm, not clear how to fit dmabufs into this.  dmabufs already have their
own file, inode and address space.  I'm not sure you can switch that
over to the per-device mapping in the first place, and even if you can I
have my doubts this is a good idea from a security point of view ...

cheers,
  Gerd
Daniel Vetter Nov. 20, 2019, 12:04 p.m. UTC | #32
On Wed, Nov 20, 2019 at 12:40 PM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
>   Hi,
>
> > > Anything building on shmem helpers should be able to use
> > > obj->filp->f_mapping, right?  So allocating an inode unconditionally
> > > doesn't look like a good plan.
> >
> > Not sure the shmem helpers forward the mmap to the underlying shmem file,
> > so not sure this is the greatest way either.
>
> I think so, shmem helpers already zap the fake offset, and this would
> not work without per-object address space I think.

That's why I think shmem helpers have a problem right now, and why
it's probably best to go back to the fake offset for everything. But
we seem to have lost Rob Herring in all this thread, so readding him.

> > > Guess I'll go look at ttm-local changes for starters and see how it
> > > goes.
> >
> > I think for ttm just consistently using the one per-device mapping for
> > everything, with all the fake offsets, is probably the quickest route.
>
> Hmm, not clear how to fit dmabufs into this.  dmabufs already have their
> own file, inode and address space.  I'm not sure you can switch that
> over to the per-device mapping in the first place, and even if you can I
> have my doubts this is a good idea from a security point of view ...

You can (plenty drivers do that already), and not sure how that breaks
security? Imo it's more consistent, since everything ends up pointing
to the same underlying resource.
-Daniel
Gerd Hoffmann Nov. 20, 2019, 12:18 p.m. UTC | #33
Hi,

> > > I think for ttm just consistently using the one per-device mapping for
> > > everything, with all the fake offsets, is probably the quickest route.
> >
> > Hmm, not clear how to fit dmabufs into this.  dmabufs already have their
> > own file, inode and address space.  I'm not sure you can switch that
> > over to the per-device mapping in the first place, and even if you can I
> > have my doubts this is a good idea from a security point of view ...
> 
> You can (plenty drivers do that already),

Have pointer(s) to code?

> and not sure how that breaks
> security?

Go try mmap(fake-offset) on the dma-buf file handle to access other
buffers of the drm device?  Hmm, thinking again, I guess the
verify-access restrictions should prevent that.

cheers,
  Gerd
Daniel Vetter Nov. 20, 2019, 12:34 p.m. UTC | #34
On Wed, Nov 20, 2019 at 1:18 PM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
>   Hi,
>
> > > > I think for ttm just consistently using the one per-device mapping for
> > > > everything, with all the fake offsets, is probably the quickest route.
> > >
> > > Hmm, not clear how to fit dmabufs into this.  dmabufs already have their
> > > own file, inode and address space.  I'm not sure you can switch that
> > > over to the per-device mapping in the first place, and even if you can I
> > > have my doubts this is a good idea from a security point of view ...
> >
> > You can (plenty drivers do that already),
>
> Have pointer(s) to code?

dma_buf_mmap() does the same trick, but the other way round: It
converts from gem mapping and fake offset to dma-buf mapping and 0
offset. I think we'd simply need the inverse.

> > and not sure how that breaks
> > security?
>
> Go try mmap(fake-offset) on the dma-buf file handle to access other
> buffers of the drm device?  Hmm, thinking again, I guess the
> verify-access restrictions should prevent that.

Ah, we're not going to replace the mapping on the dma-buf file. Only
the file of the vma structure. Doing the former would indeed be pretty
bad from a security pov. So don't do what amdgpu_gem_prime_export
does, that's the bad stuff :-)
-Daniel
Gerd Hoffmann Nov. 20, 2019, 1:08 p.m. UTC | #35
Hi,

> Ah, we're not going to replace the mapping on the dma-buf file. Only
> the file of the vma structure. Doing the former would indeed be pretty
> bad from a security pov.

Now where do I get a filp from?  Can I just call drm_open?

cheers,
  Gerd
Daniel Vetter Nov. 20, 2019, 1:40 p.m. UTC | #36
On Wed, Nov 20, 2019 at 2:08 PM Gerd Hoffmann <kraxel@redhat.com> wrote:
> > Ah, we're not going to replace the mapping on the dma-buf file. Only
> > the file of the vma structure. Doing the former would indeed be pretty
> > bad from a security pov.
>
> Now where do I get a filp from?  Can I just call drm_open?

Hm, now I wonder whether it's maybe ok to just exchange the
filp->f_mapping. As long as we don't mix up the kinds of mapping and
page-cache management that can happon on a given address_space
structure (that's why I'm not keeon the shmem mapping reused, since
shmem uses the same address_space structure internally to manage the
page allocations - address_space both contains the page cache for a
file, and also the reverse mapping information). So kinda what
drm_open does, except we do that to the dma-buf file. So exactly what
amdgpu is doing and that I just complained about :-)

Aside: the amdgpu isn't great because it's racy, userspace could have
guessed the fd and already started an mmap before we managed to update
stuff. But aside from that maybe rolling out the amdgpu trick for
everyone is the right way?
-Daniel
Gerd Hoffmann Nov. 21, 2019, 8:02 a.m. UTC | #37
Hi,

> > update-object-after-move works fine.
> > 
> > try zap mappings with madvise(dontneed) has no bad effects (after vram
> > move, trying to force re-creating the ptes).
> 
> Well if it's broken the zapping wouldn't work :-)
> 
> > didn't try the memory pressure thing yet.
> 
> I'm surprised ... and I have no idea how/why it keeps working.
> 
> For my paranoia, can you instrument the ttm page fault handler, and double
> check that we get new faults after the move, and set up new ptes for the
> same old mapping, but now pointing at the new place in vram?

Hmm, only the drm device mapping is faulted in after moving it,
the dma-buf mapping is not.  Fixed by:

-------------------------- cut here ------------------------
From 3a7f6c6dbf3b1e4b412c2b283b2ea4edff9f33b5 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 21 Nov 2019 08:39:17 +0100
Subject: [PATCH] drm: share address space for dma bufs

---
 drivers/gpu/drm/drm_prime.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 0814211b0f3f..07c88d2aedee 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -240,6 +240,7 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
 struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
 				      struct dma_buf_export_info *exp_info)
 {
+	struct drm_gem_object *obj = exp_info->priv;
 	struct dma_buf *dma_buf;
 
 	dma_buf = dma_buf_export(exp_info);
@@ -247,7 +248,8 @@ struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
 		return dma_buf;
 
 	drm_dev_get(dev);
-	drm_gem_object_get(exp_info->priv);
+	drm_gem_object_get(obj);
+	dma_buf->file->f_mapping = obj->dev->anon_inode->i_mapping;
 
 	return dma_buf;
 }
Gerd Hoffmann Nov. 21, 2019, 8:10 a.m. UTC | #38
Hi,

> Aside: the amdgpu isn't great because it's racy, userspace could have
> guessed the fd and already started an mmap before we managed to update
> stuff.

Can't see that race.  When I read the code correctly the fd is created
and installed (using dma_buf_fd) only after dmabuf setup is finished.

cheers,
  Gerd
Daniel Vetter Nov. 21, 2019, 8:47 a.m. UTC | #39
On Thu, Nov 21, 2019 at 09:10:21AM +0100, Gerd Hoffmann wrote:
>   Hi,
> 
> > Aside: the amdgpu isn't great because it's racy, userspace could have
> > guessed the fd and already started an mmap before we managed to update
> > stuff.
> 
> Can't see that race.  When I read the code correctly the fd is created
> and installed (using dma_buf_fd) only after dmabuf setup is finished.

Right, I mixed things up. Looks all good.
-Daniel
Daniel Vetter Nov. 21, 2019, 8:49 a.m. UTC | #40
On Thu, Nov 21, 2019 at 09:02:59AM +0100, Gerd Hoffmann wrote:
>   Hi,
> 
> > > update-object-after-move works fine.
> > > 
> > > try zap mappings with madvise(dontneed) has no bad effects (after vram
> > > move, trying to force re-creating the ptes).
> > 
> > Well if it's broken the zapping wouldn't work :-)
> > 
> > > didn't try the memory pressure thing yet.
> > 
> > I'm surprised ... and I have no idea how/why it keeps working.
> > 
> > For my paranoia, can you instrument the ttm page fault handler, and double
> > check that we get new faults after the move, and set up new ptes for the
> > same old mapping, but now pointing at the new place in vram?
> 
> Hmm, only the drm device mapping is faulted in after moving it,
> the dma-buf mapping is not.  Fixed by:

Ah yes, that's more what I'd expect to happen, and the below is what I'd
expect to fix things up. I think we should move it up ahead of the device
callback (so that drivers can overwrite) and then push as a fix. Separate
from a possible patch to undo the fake offset removal.
-Daniel

> 
> -------------------------- cut here ------------------------
> From 3a7f6c6dbf3b1e4b412c2b283b2ea4edff9f33b5 Mon Sep 17 00:00:00 2001
> From: Gerd Hoffmann <kraxel@redhat.com>
> Date: Thu, 21 Nov 2019 08:39:17 +0100
> Subject: [PATCH] drm: share address space for dma bufs
> 
> ---
>  drivers/gpu/drm/drm_prime.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index 0814211b0f3f..07c88d2aedee 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -240,6 +240,7 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
>  struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
>  				      struct dma_buf_export_info *exp_info)
>  {
> +	struct drm_gem_object *obj = exp_info->priv;
>  	struct dma_buf *dma_buf;
>  
>  	dma_buf = dma_buf_export(exp_info);
> @@ -247,7 +248,8 @@ struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
>  		return dma_buf;
>  
>  	drm_dev_get(dev);
> -	drm_gem_object_get(exp_info->priv);
> +	drm_gem_object_get(obj);
> +	dma_buf->file->f_mapping = obj->dev->anon_inode->i_mapping;
>  
>  	return dma_buf;
>  }
> -- 
> 2.18.1
> 
> -------------------------- cut here ------------------------
> 
> git branch: https://git.kraxel.org/cgit/linux/log/?h=drm-mmap-debug
> 
> cheers,
>   Gerd
>
Gerd Hoffmann Nov. 21, 2019, 10:18 a.m. UTC | #41
On Thu, Nov 21, 2019 at 09:49:53AM +0100, Daniel Vetter wrote:
> On Thu, Nov 21, 2019 at 09:02:59AM +0100, Gerd Hoffmann wrote:
> >   Hi,
> > 
> > > > update-object-after-move works fine.
> > > > 
> > > > try zap mappings with madvise(dontneed) has no bad effects (after vram
> > > > move, trying to force re-creating the ptes).
> > > 
> > > Well if it's broken the zapping wouldn't work :-)
> > > 
> > > > didn't try the memory pressure thing yet.
> > > 
> > > I'm surprised ... and I have no idea how/why it keeps working.
> > > 
> > > For my paranoia, can you instrument the ttm page fault handler, and double
> > > check that we get new faults after the move, and set up new ptes for the
> > > same old mapping, but now pointing at the new place in vram?
> > 
> > Hmm, only the drm device mapping is faulted in after moving it,
> > the dma-buf mapping is not.  Fixed by:
> 
> Ah yes, that's more what I'd expect to happen, and the below is what I'd
> expect to fix things up. I think we should move it up ahead of the device
> callback (so that drivers can overwrite) and then push as a fix. Separate
> from a possible patch to undo the fake offset removal.
> -Daniel

Is there a more elegant way than copying the intel list on non-intel
patches to kick intel ci?

cheers,
  Gerd
Daniel Vetter Nov. 21, 2019, 10:36 a.m. UTC | #42
On Thu, Nov 21, 2019 at 11:18 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
> On Thu, Nov 21, 2019 at 09:49:53AM +0100, Daniel Vetter wrote:
> > On Thu, Nov 21, 2019 at 09:02:59AM +0100, Gerd Hoffmann wrote:
> > >   Hi,
> > >
> > > > > update-object-after-move works fine.
> > > > >
> > > > > try zap mappings with madvise(dontneed) has no bad effects (after vram
> > > > > move, trying to force re-creating the ptes).
> > > >
> > > > Well if it's broken the zapping wouldn't work :-)
> > > >
> > > > > didn't try the memory pressure thing yet.
> > > >
> > > > I'm surprised ... and I have no idea how/why it keeps working.
> > > >
> > > > For my paranoia, can you instrument the ttm page fault handler, and double
> > > > check that we get new faults after the move, and set up new ptes for the
> > > > same old mapping, but now pointing at the new place in vram?
> > >
> > > Hmm, only the drm device mapping is faulted in after moving it,
> > > the dma-buf mapping is not.  Fixed by:
> >
> > Ah yes, that's more what I'd expect to happen, and the below is what I'd
> > expect to fix things up. I think we should move it up ahead of the device
> > callback (so that drivers can overwrite) and then push as a fix. Separate
> > from a possible patch to undo the fake offset removal.
> > -Daniel
>
> Is there a more elegant way than copying the intel list on non-intel
> patches to kick intel ci?

Nope, not really.
-Daniel
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 56f42e0f2584..2f2b889096b0 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1106,6 +1106,9 @@  int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
 		return -EINVAL;
 
 	if (obj->funcs && obj->funcs->mmap) {
+		/* Remove the fake offset */
+		vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
+
 		ret = obj->funcs->mmap(obj, vma);
 		if (ret)
 			return ret;
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index a878c787b867..e8061c64c480 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -542,9 +542,6 @@  int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
 	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
 	vma->vm_ops = &drm_gem_shmem_vm_ops;
 
-	/* Remove the fake offset */
-	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 1a9db691f954..08902c7290a5 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -482,6 +482,13 @@  EXPORT_SYMBOL(ttm_bo_mmap);
 int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
 {
 	ttm_bo_get(bo);
+
+	/*
+	 * FIXME: &drm_gem_object_funcs.mmap is called with the fake offset
+	 * removed. Add it back here until the rest of TTM works without it.
+	 */
+	vma->vm_pgoff += drm_vma_node_start(&bo->base.vma_node);
+
 	ttm_bo_mmap_vma_setup(bo, vma);
 	return 0;
 }
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index e71f75a2ab57..c56cbb3509e0 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -159,7 +159,9 @@  struct drm_gem_object_funcs {
 	 *
 	 * The callback is used by by both drm_gem_mmap_obj() and
 	 * drm_gem_prime_mmap().  When @mmap is present @vm_ops is not
-	 * used, the @mmap callback must set vma->vm_ops instead.
+	 * used, the @mmap callback must set vma->vm_ops instead. The @mmap
+	 * callback is always called with a 0 offset. The caller will remove
+	 * the fake offset as necessary.
 	 *
 	 */
 	int (*mmap)(struct drm_gem_object *obj, struct vm_area_struct *vma);