Skip to content

Commit a431174

Browse files
committed
drm/i915/userptr: Never allow userptr into the mappable GGTT
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]
1 parent 99785b8 commit a431174

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
@@ -343,6 +343,7 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf)
343343
/* fallthrough */
344344
case -EIO: /* shmemfs failure from swap device */
345345
case -EFAULT: /* purged object */
346+
case -ENODEV: /* bad object, how did you get here! */
346347
return VM_FAULT_SIGBUS;
347348

348349
case -ENOSPC: /* shmemfs allocation failure */
@@ -466,10 +467,16 @@ i915_gem_mmap_gtt(struct drm_file *file,
466467
if (!obj)
467468
return -ENOENT;
468469

470+
if (i915_gem_object_never_bind_ggtt(obj)) {
471+
ret = -ENODEV;
472+
goto out;
473+
}
474+
469475
ret = create_mmap_offset(obj);
470476
if (ret == 0)
471477
*offset = drm_vma_node_offset_addr(&obj->base.vma_node);
472478

479+
out:
473480
i915_gem_object_put(obj);
474481
return ret;
475482
}

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
@@ -32,7 +32,8 @@ struct drm_i915_gem_object_ops {
3232
#define I915_GEM_OBJECT_HAS_STRUCT_PAGE BIT(0)
3333
#define I915_GEM_OBJECT_IS_SHRINKABLE BIT(1)
3434
#define I915_GEM_OBJECT_IS_PROXY BIT(2)
35-
#define I915_GEM_OBJECT_ASYNC_CANCEL BIT(3)
35+
#define I915_GEM_OBJECT_NO_GGTT BIT(3)
36+
#define I915_GEM_OBJECT_ASYNC_CANCEL BIT(4)
3637

3738
/* Interface between the GEM object and its backing storage.
3839
* 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
@@ -710,6 +710,7 @@ i915_gem_userptr_dmabuf_export(struct drm_i915_gem_object *obj)
710710
static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
711711
.flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE |
712712
I915_GEM_OBJECT_IS_SHRINKABLE |
713+
I915_GEM_OBJECT_NO_GGTT |
713714
I915_GEM_OBJECT_ASYNC_CANCEL,
714715
.get_pages = i915_gem_userptr_get_pages,
715716
.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
@@ -970,6 +970,9 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
970970

971971
lockdep_assert_held(&obj->base.dev->struct_mutex);
972972

973+
if (i915_gem_object_never_bind_ggtt(obj))
974+
return ERR_PTR(-ENODEV);
975+
973976
if (flags & PIN_MAPPABLE &&
974977
(!view || view->type == I915_GGTT_VIEW_NORMAL)) {
975978
/* If the required space is larger than the available

0 commit comments

Comments
 (0)