diff mbox

drm: Give the DRM device's anon_inode a unique lockclass for its mmap_rswem

Message ID 20171211103954.21213-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson Dec. 11, 2017, 10:39 a.m. UTC
Teach lockdep to track the device's internal mmapping separately
from the generic lockclass over all other inodes. Since this is device
private we wish to allow a different locking hierarchy than is typified
by the requirement for the mmap_rwsem being the outermost lock for
handling pagefaults. By giving the internal mmap_rwsem a distinct
lockclass, lockdep can identify it and learn/enforce its distinct locking
requirements.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104209
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_drv.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

Comments

Daniel Vetter Dec. 11, 2017, 5:20 p.m. UTC | #1
On Mon, Dec 11, 2017 at 11:39 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> Teach lockdep to track the device's internal mmapping separately
> from the generic lockclass over all other inodes. Since this is device
> private we wish to allow a different locking hierarchy than is typified
> by the requirement for the mmap_rwsem being the outermost lock for
> handling pagefaults. By giving the internal mmap_rwsem a distinct
> lockclass, lockdep can identify it and learn/enforce its distinct locking
> requirements.
>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104209
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>

I think both the commit message and comment are a bit too fluffy - the
critical bit is that we're biting ourselves on gtt mmaps from
usersptr, and that's explicitly not allowed exactly because it would
deadlock.

I'm also not sure it's a good idea to implement this in generic code,
since this is a very i915 specific issue, and other drivers (who might
be a lot less sloppy here) will now no longer get reports about this
deadlock.

Aside from that I'm not really sure why you think the bugzilla link is
a false positive: The mapping->rwsem is the one for the gtt in both
cases I think.
-Daniel

> ---
>  drivers/gpu/drm/drm_drv.c | 17 ++++++++++++++++-
>  1 file changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 9acc1e157813..21ad06c3d684 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -393,6 +393,7 @@ static struct file_system_type drm_fs_type = {
>
>  static struct inode *drm_fs_inode_new(void)
>  {
> +       static struct lock_class_key lockclass;
>         struct inode *inode;
>         int r;
>
> @@ -403,8 +404,22 @@ static struct inode *drm_fs_inode_new(void)
>         }
>
>         inode = alloc_anon_inode(drm_fs_mnt->mnt_sb);
> -       if (IS_ERR(inode))
> +       if (IS_ERR(inode)) {
>                 simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
> +               return inode;
> +       }
> +
> +       /*
> +        * Teach lockdep to track the device's internal mmapping separately
> +        * from all other inodes. Since this is device private we wish to
> +        * allow a different locking hierarchy than is typified by the
> +        * requirement for the mmap_rwsem being the outermost lock for
> +        * handling pagefaults. By giving the internal mmap_rwsem a distinct
> +        * lockclass, lockdep can identify it and thereby learn and enforce its
> +        * distinct locking requirements.
> +        */
> +       lockdep_set_class_and_name(&inode->i_mapping->i_mmap_rwsem,
> +                                  &lockclass, "drm_fs_inode");
>
>         return inode;
>  }
> --
> 2.15.1
>
Chris Wilson Dec. 11, 2017, 5:27 p.m. UTC | #2
Quoting Daniel Vetter (2017-12-11 17:20:32)
> On Mon, Dec 11, 2017 at 11:39 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> > Teach lockdep to track the device's internal mmapping separately
> > from the generic lockclass over all other inodes. Since this is device
> > private we wish to allow a different locking hierarchy than is typified
> > by the requirement for the mmap_rwsem being the outermost lock for
> > handling pagefaults. By giving the internal mmap_rwsem a distinct
> > lockclass, lockdep can identify it and learn/enforce its distinct locking
> > requirements.
> >
> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104209
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> I think both the commit message and comment are a bit too fluffy - the
> critical bit is that we're biting ourselves on gtt mmaps from
> usersptr, and that's explicitly not allowed exactly because it would
> deadlock.
> 
> I'm also not sure it's a good idea to implement this in generic code,
> since this is a very i915 specific issue, and other drivers (who might
> be a lot less sloppy here) will now no longer get reports about this
> deadlock.

I was thinking that in a more general sense manipulating of the
vma_manager's inode is independent of the processes's mappings. As such
we do not want to tie the two together and force them to conform to the
same rules, because the core mapping semaphore will be held on entry to
driver code, but the internal mapping will be used from within driver
code.
-Chris
Daniel Vetter Dec. 11, 2017, 5:44 p.m. UTC | #3
On Mon, Dec 11, 2017 at 6:27 PM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> Quoting Daniel Vetter (2017-12-11 17:20:32)
>> On Mon, Dec 11, 2017 at 11:39 AM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
>> > Teach lockdep to track the device's internal mmapping separately
>> > from the generic lockclass over all other inodes. Since this is device
>> > private we wish to allow a different locking hierarchy than is typified
>> > by the requirement for the mmap_rwsem being the outermost lock for
>> > handling pagefaults. By giving the internal mmap_rwsem a distinct
>> > lockclass, lockdep can identify it and learn/enforce its distinct locking
>> > requirements.
>> >
>> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104209
>> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
>> > Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
>>
>> I think both the commit message and comment are a bit too fluffy - the
>> critical bit is that we're biting ourselves on gtt mmaps from
>> usersptr, and that's explicitly not allowed exactly because it would
>> deadlock.
>>
>> I'm also not sure it's a good idea to implement this in generic code,
>> since this is a very i915 specific issue, and other drivers (who might
>> be a lot less sloppy here) will now no longer get reports about this
>> deadlock.
>
> I was thinking that in a more general sense manipulating of the
> vma_manager's inode is independent of the processes's mappings. As such
> we do not want to tie the two together and force them to conform to the
> same rules, because the core mapping semaphore will be held on entry to
> driver code, but the internal mapping will be used from within driver
> code.

I think they're the same locks really. Maybe I'm missing something,
but I thought the mapping->rwsem we get on mmap/fault is exactly the
one we want/need to use for zap_pte.

Looking at the bugzilla trace I think the deadlock happens when the
i915_gem_userptr_mn_invalidate_range_start callback calls
flush_workqueue for a range that is not itself not allowed to be
userptr-mapped. But because it does that, we end up in a deadlock. I
think if the userptr callback would checkthe range it gets against all
the userptr mappings, we'd avoid this deadlock: userptr is not allowed
to map a gtt range, which means this should avoid calling
flush_workqueue while holding our drm mapping->rwsem.

So there seems to be a real deadlock, at least in my current understanding.

Of course if we'd fix that deadlock we'd still have lockdep
complaining, but maybe the deadlock fix also gets rid of the lockdep
splat (but that would be more rework than just making the flush_work
conditional).
-Daniel
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 9acc1e157813..21ad06c3d684 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -393,6 +393,7 @@  static struct file_system_type drm_fs_type = {
 
 static struct inode *drm_fs_inode_new(void)
 {
+	static struct lock_class_key lockclass;
 	struct inode *inode;
 	int r;
 
@@ -403,8 +404,22 @@  static struct inode *drm_fs_inode_new(void)
 	}
 
 	inode = alloc_anon_inode(drm_fs_mnt->mnt_sb);
-	if (IS_ERR(inode))
+	if (IS_ERR(inode)) {
 		simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
+		return inode;
+	}
+
+	/*
+	 * Teach lockdep to track the device's internal mmapping separately
+	 * from all other inodes. Since this is device private we wish to
+	 * allow a different locking hierarchy than is typified by the
+	 * requirement for the mmap_rwsem being the outermost lock for
+	 * handling pagefaults. By giving the internal mmap_rwsem a distinct
+	 * lockclass, lockdep can identify it and thereby learn and enforce its
+	 * distinct locking requirements.
+	 */
+	lockdep_set_class_and_name(&inode->i_mapping->i_mmap_rwsem,
+				   &lockclass, "drm_fs_inode");
 
 	return inode;
 }