Skip to content

Commit d9e6f75

Browse files
icklesmb49
authored andcommitted
drm/i915/userptr: Never allow userptr into the mappable GGTT
BugLink: https://bugs.launchpad.net/bugs/1850456 commit 4f2a572 upstream. Daniel Vetter uncovered a nasty cycle in using the mmu-notifiers to invalidate userptr objects which also happen to be pulled into GGTT mmaps. That is when we unbind the userptr object (on mmu invalidation), we revoke all CPU mmaps, which may then recurse into mmu invalidation. We looked for ways of breaking the cycle, but the revocation on invalidation is required and cannot be avoided. The only solution we could see was to not allow such GGTT bindings of userptr objects in the first place. In practice, no one really wants to use a GGTT mmapping of a CPU pointer... Just before Daniel's explosive lockdep patches land in v5.4-rc1, we got a genuine blip from CI: <4>[ 246.793958] ====================================================== <4>[ 246.793972] WARNING: possible circular locking dependency detected <4>[ 246.793989] 5.3.0-gbd6c56f50d15-drmtip_372+ #1 Tainted: G U <4>[ 246.794003] ------------------------------------------------------ <4>[ 246.794017] kswapd0/145 is trying to acquire lock: <4>[ 246.794030] 000000003f565be6 (&dev->struct_mutex/1){+.+.}, at: userptr_mn_invalidate_range_start+0x18f/0x220 [i915] <4>[ 246.794250] but task is already holding lock: <4>[ 246.794263] 000000001799cef9 (&anon_vma->rwsem){++++}, at: page_lock_anon_vma_read+0xe6/0x2a0 <4>[ 246.794291] which lock already depends on the new lock. <4>[ 246.794307] the existing dependency chain (in reverse order) is: <4>[ 246.794322] -> #3 (&anon_vma->rwsem){++++}: <4>[ 246.794344] down_write+0x33/0x70 <4>[ 246.794357] __vma_adjust+0x3d9/0x7b0 <4>[ 246.794370] __split_vma+0x16a/0x180 <4>[ 246.794385] mprotect_fixup+0x2a5/0x320 <4>[ 246.794399] do_mprotect_pkey+0x208/0x2e0 <4>[ 246.794413] __x64_sys_mprotect+0x16/0x20 <4>[ 246.794429] do_syscall_64+0x55/0x1c0 <4>[ 246.794443] entry_SYSCALL_64_after_hwframe+0x49/0xbe <4>[ 246.794456] -> #2 (&mapping->i_mmap_rwsem){++++}: <4>[ 246.794478] down_write+0x33/0x70 <4>[ 246.794493] unmap_mapping_pages+0x48/0x130 <4>[ 246.794519] i915_vma_revoke_mmap+0x81/0x1b0 [i915] <4>[ 246.794519] i915_vma_unbind+0x11d/0x4a0 [i915] <4>[ 246.794519] i915_vma_destroy+0x31/0x300 [i915] <4>[ 246.794519] __i915_gem_free_objects+0xb8/0x4b0 [i915] <4>[ 246.794519] drm_file_free.part.0+0x1e6/0x290 <4>[ 246.794519] drm_release+0xa6/0xe0 <4>[ 246.794519] __fput+0xc2/0x250 <4>[ 246.794519] task_work_run+0x82/0xb0 <4>[ 246.794519] do_exit+0x35b/0xdb0 <4>[ 246.794519] do_group_exit+0x34/0xb0 <4>[ 246.794519] __x64_sys_exit_group+0xf/0x10 <4>[ 246.794519] do_syscall_64+0x55/0x1c0 <4>[ 246.794519] entry_SYSCALL_64_after_hwframe+0x49/0xbe <4>[ 246.794519] -> #1 (&vm->mutex){+.+.}: <4>[ 246.794519] i915_gem_shrinker_taints_mutex+0x6d/0xe0 [i915] <4>[ 246.794519] i915_address_space_init+0x9f/0x160 [i915] <4>[ 246.794519] i915_ggtt_init_hw+0x55/0x170 [i915] <4>[ 246.794519] i915_driver_probe+0xc9f/0x1620 [i915] <4>[ 246.794519] i915_pci_probe+0x43/0x1b0 [i915] <4>[ 246.794519] pci_device_probe+0x9e/0x120 <4>[ 246.794519] really_probe+0xea/0x3d0 <4>[ 246.794519] driver_probe_device+0x10b/0x120 <4>[ 246.794519] device_driver_attach+0x4a/0x50 <4>[ 246.794519] __driver_attach+0x97/0x130 <4>[ 246.794519] bus_for_each_dev+0x74/0xc0 <4>[ 246.794519] bus_add_driver+0x13f/0x210 <4>[ 246.794519] driver_register+0x56/0xe0 <4>[ 246.794519] do_one_initcall+0x58/0x300 <4>[ 246.794519] do_init_module+0x56/0x1f6 <4>[ 246.794519] load_module+0x25bd/0x2a40 <4>[ 246.794519] __se_sys_finit_module+0xd3/0xf0 <4>[ 246.794519] do_syscall_64+0x55/0x1c0 <4>[ 246.794519] entry_SYSCALL_64_after_hwframe+0x49/0xbe <4>[ 246.794519] -> #0 (&dev->struct_mutex/1){+.+.}: <4>[ 246.794519] __lock_acquire+0x15d8/0x1e90 <4>[ 246.794519] lock_acquire+0xa6/0x1c0 <4>[ 246.794519] __mutex_lock+0x9d/0x9b0 <4>[ 246.794519] userptr_mn_invalidate_range_start+0x18f/0x220 [i915] <4>[ 246.794519] __mmu_notifier_invalidate_range_start+0x85/0x110 <4>[ 246.794519] try_to_unmap_one+0x76b/0x860 <4>[ 246.794519] rmap_walk_anon+0x104/0x280 <4>[ 246.794519] try_to_unmap+0xc0/0xf0 <4>[ 246.794519] shrink_page_list+0x561/0xc10 <4>[ 246.794519] shrink_inactive_list+0x220/0x440 <4>[ 246.794519] shrink_node_memcg+0x36e/0x740 <4>[ 246.794519] shrink_node+0xcb/0x490 <4>[ 246.794519] balance_pgdat+0x241/0x580 <4>[ 246.794519] kswapd+0x16c/0x530 <4>[ 246.794519] kthread+0x119/0x130 <4>[ 246.794519] ret_from_fork+0x24/0x50 <4>[ 246.794519] other info that might help us debug this: <4>[ 246.794519] Chain exists of: &dev->struct_mutex/1 --> &mapping->i_mmap_rwsem --> &anon_vma->rwsem <4>[ 246.794519] Possible unsafe locking scenario: <4>[ 246.794519] CPU0 CPU1 <4>[ 246.794519] ---- ---- <4>[ 246.794519] lock(&anon_vma->rwsem); <4>[ 246.794519] lock(&mapping->i_mmap_rwsem); <4>[ 246.794519] lock(&anon_vma->rwsem); <4>[ 246.794519] lock(&dev->struct_mutex/1); <4>[ 246.794519] *** DEADLOCK *** v2: Say no to mmap_ioctl Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111744 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111870 Signed-off-by: Chris Wilson <[email protected]> Cc: Tvrtko Ursulin <[email protected]> Cc: Daniel Vetter <[email protected]> Cc: [email protected] Reviewed-by: Tvrtko Ursulin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] (cherry picked from commit a431174) Signed-off-by: Rodrigo Vivi <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Connor Kuehl <[email protected]> Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
1 parent eacb376 commit d9e6f75

File tree

5 files changed

+19
-1
lines changed

5 files changed

+19
-1
lines changed

drivers/gpu/drm/i915/gem/i915_gem_mman.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf)
365365
return VM_FAULT_OOM;
366366
case -ENOSPC:
367367
case -EFAULT:
368+
case -ENODEV: /* bad object, how did you get here! */
368369
return VM_FAULT_SIGBUS;
369370
default:
370371
WARN_ONCE(ret, "unhandled error in %s: %i\n", __func__, ret);
@@ -475,10 +476,16 @@ i915_gem_mmap_gtt(struct drm_file *file,
475476
if (!obj)
476477
return -ENOENT;
477478

479+
if (i915_gem_object_never_bind_ggtt(obj)) {
480+
ret = -ENODEV;
481+
goto out;
482+
}
483+
478484
ret = create_mmap_offset(obj);
479485
if (ret == 0)
480486
*offset = drm_vma_node_offset_addr(&obj->base.vma_node);
481487

488+
out:
482489
i915_gem_object_put(obj);
483490
return ret;
484491
}

drivers/gpu/drm/i915/gem/i915_gem_object.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ i915_gem_object_is_proxy(const struct drm_i915_gem_object *obj)
152152
return obj->ops->flags & I915_GEM_OBJECT_IS_PROXY;
153153
}
154154

155+
static inline bool
156+
i915_gem_object_never_bind_ggtt(const struct drm_i915_gem_object *obj)
157+
{
158+
return obj->ops->flags & I915_GEM_OBJECT_NO_GGTT;
159+
}
160+
155161
static inline bool
156162
i915_gem_object_needs_async_cancel(const struct drm_i915_gem_object *obj)
157163
{

drivers/gpu/drm/i915/gem/i915_gem_object_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ struct drm_i915_gem_object_ops {
3131
#define I915_GEM_OBJECT_HAS_STRUCT_PAGE BIT(0)
3232
#define I915_GEM_OBJECT_IS_SHRINKABLE BIT(1)
3333
#define I915_GEM_OBJECT_IS_PROXY BIT(2)
34-
#define I915_GEM_OBJECT_ASYNC_CANCEL BIT(3)
34+
#define I915_GEM_OBJECT_NO_GGTT BIT(3)
35+
#define I915_GEM_OBJECT_ASYNC_CANCEL BIT(4)
3536

3637
/* Interface between the GEM object and its backing storage.
3738
* get_pages() is called once prior to the use of the associated set

drivers/gpu/drm/i915/gem/i915_gem_userptr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ i915_gem_userptr_dmabuf_export(struct drm_i915_gem_object *obj)
694694
static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
695695
.flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE |
696696
I915_GEM_OBJECT_IS_SHRINKABLE |
697+
I915_GEM_OBJECT_NO_GGTT |
697698
I915_GEM_OBJECT_ASYNC_CANCEL,
698699
.get_pages = i915_gem_userptr_get_pages,
699700
.put_pages = i915_gem_userptr_put_pages,

drivers/gpu/drm/i915/i915_gem.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,9 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
10441044

10451045
lockdep_assert_held(&obj->base.dev->struct_mutex);
10461046

1047+
if (i915_gem_object_never_bind_ggtt(obj))
1048+
return ERR_PTR(-ENODEV);
1049+
10471050
if (flags & PIN_MAPPABLE &&
10481051
(!view || view->type == I915_GGTT_VIEW_NORMAL)) {
10491052
/* If the required space is larger than the available

0 commit comments

Comments
 (0)