diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-12-02 03:41:13 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-12-02 03:41:13 +0000 |
commit | 50de43aba5d4474723b4571b57f533310777b15a (patch) | |
tree | 69c4a32458151c2f49c2784344be6903a83ac8a4 | |
parent | a47c980f74e2fdc21c1cb38a9476b13ab1a668b4 (diff) |
drm/i915/userptr: Try to acquire the page lock around set_page_dirty()
From Chris Wilson
e80e88ef6057c7947409bda9898387d25e54aaa9 in linux 4.19.y/4.19.87
2d691aeca4aecbb8d0414a777a46981a8e142b05 in mainline linux
-rw-r--r-- | sys/dev/pci/drm/i915/i915_gem_userptr.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/sys/dev/pci/drm/i915/i915_gem_userptr.c b/sys/dev/pci/drm/i915/i915_gem_userptr.c index 9a65830ede0..538b7415605 100644 --- a/sys/dev/pci/drm/i915/i915_gem_userptr.c +++ b/sys/dev/pci/drm/i915/i915_gem_userptr.c @@ -693,8 +693,28 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj, i915_gem_gtt_finish_pages(obj, pages); 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 + * the page in order to dirty it -- holding + * 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(page); + unlock_page(page); + } mark_page_accessed(page); put_page(page); |