Quoting Chris Wilson (2019-07-16 13:49:27) > Following a try_to_unmap() we may want to remove the userptr and so call > put_pages(). However, try_to_unmap() acquires the page lock and so we > must avoid recursively locking the pages ourselves -- which means that > we cannot safely acquire the lock around set_page_dirty(). Since we > can't be sure of the lock, we have to risk skip dirtying the page, or > else risk calling set_page_dirty() without a lock and so risk fs > corruption. > > Reported-by: Lionel Landwerlin <lionel.g.landwerlin@xxxxxxxxx> > Fixes: cb6d7c7dc7ff ("drm/i915/userptr: Acquire the page lock around set_page_dirty()") > Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> > Cc: Lionel Landwerlin <lionel.g.landwerlin@xxxxxxxxx> > Cc: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> > Cc: stable@xxxxxxxxxxxxxxx > --- > drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 16 ++++++++++++++-- > 1 file changed, 14 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c > index b9d2bb15e4a6..1ad2047a6dbd 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c > @@ -672,7 +672,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj, > obj->mm.dirty = false; > > for_each_sgt_page(page, sgt_iter, pages) { > - if (obj->mm.dirty) > + if (obj->mm.dirty && trylock_page(page)) { > /* > * As this may not be anonymous memory (e.g. shmem) > * but exist on a real mapping, we have to lock > @@ -680,8 +680,20 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj, > * the page reference is not sufficient to > * prevent the inode from being truncated. > * Play safe and take the lock. > + * > + * However...! > + * > + * The mmu-notifier can be invalidated for a > + * migrate_page, that is alreadying holding the lock > + * on the page. Such a try_to_unmap() will result > + * in us calling put_pages() and so recursively try > + * to lock the page. We avoid that deadlock with > + * a trylock_page() and in exchange we risk missing > + * some page dirtying. > */ > - set_page_dirty_lock(page); > + set_page_dirty(page); > + unlock_page(page); > + } It really seems like we have no choice but to only call set_page_dirty() while under the page lock, and the only way we can guarantee that without recursion is with a trylock... https://bugs.freedesktop.org/show_bug.cgi?id=112012 -Chris _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx