aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-09-04 05:45:50 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-09-05 08:47:59 -0400
commit57094f82465002fbde1447e2fd850e1179bf6d86 (patch)
tree92d0dfd56a91016aa1fa78eb05d39f63821da027 /drivers/gpu
parenta2dc53e7dc4d22f20aecdfa10f85004de442e4d0 (diff)
drm/i915: Hold an object reference whilst we shrink it
Whilst running the shrinker, we need to hold a reference as we unbind the objects, or else we may end up waiting for and retiring requests, which in turn may result in this object being freed. This is very similar to the eviction code which also has to be very careful to keep a reference to its objects as it retires and unbinds them. Another similarity, that Ben pointed out, is that as we may call retire-requests, the unbound_list is outside of our control. We must only process a single element of that list at a time, that is we can not rely on the "safe" next pointer being valid after a call to i915_vma_unbind(). BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [<ffffffffa0082892>] i915_gem_gtt_finish_object+0x68/0xbd [i915] PGD 758d3067 PUD ac0d6067 PMD 0 Oops: 0000 [#1] SMP Modules linked in: dm_mod snd_hda_codec_realtek iTCO_wdt iTCO_vendor_support pcspkr snd_hda_intel i2c_i801 snd_hda_codec snd_hwdep snd_pcm snd_page_alloc snd_timer snd lpc_ich mfd_core soundcore battery ac option usb_wwan usbserial uvcvideo videobuf2_vmalloc videobuf2_memops videobuf2_core videodev i915 video button drm_kms_helper drm acpi_cpufreq mperf freq_table CPU: 1 PID: 16835 Comm: fbo-maxsize Not tainted 3.11.0-rc7_nightlytop_8fdad4_20130902_+ #7977 task: ffff8800712106d0 ti: ffff880028e4a000 task.ti: ffff880028e4a000 RIP: 0010:[<ffffffffa0082892>] [<ffffffffa0082892>] i915_gem_gtt_finish_object+0x68/0xbd [i915] RSP: 0018:ffff880028e4b9e8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff880145734000 RCX: ffff880145735328 RDX: ffff8801457353fc RSI: 0000000000000000 RDI: ffff88007597cc00 RBP: ffff88007597cc00 R08: 0000000000000001 R09: ffff88014f257f00 R10: ffffea0001d65f00 R11: 0000000000bba60b R12: ffff880149e5b000 R13: ffff880145734001 R14: ffff88007597ccc8 R15: ffff88007597cc00 FS: 00007ff5bc919740(0000) GS:ffff88014f240000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000008 CR3: 0000000028f4c000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Stack: 0000000000000000 ffff88007597cc00 ffff8801440d6840 0000000000000000 ffff880145734000 ffffffffa007c854 0000000000000010 ffff88007597c900 0000000000018000 00000000004a1201 ffff88007597cc60 ffffffffa007d183 Call Trace: [<ffffffffa007c854>] ? i915_vma_unbind+0xe2/0x1d1 [i915] [<ffffffffa007d183>] ? __i915_gem_shrink+0xf1/0x162 [i915] [<ffffffffa007d2ee>] ? i915_gem_object_get_pages_gtt+0xfa/0x303 [i915] [<ffffffffa00795f4>] ? i915_gem_object_get_pages+0x54/0x89 [i915] [<ffffffffa007cbda>] ? i915_gem_object_pin+0x238/0x5ce [i915] [<ffffffff812cba5f>] ? __sg_page_iter_next+0x2b/0x58 [<ffffffffa0082056>] ? gen6_ppgtt_insert_entries+0xf2/0x114 [i915] [<ffffffffa007fe4b>] ? i915_gem_execbuffer_reserve_vma.isra.13+0x79/0x18d [i915] [<ffffffffa008017c>] ? i915_gem_execbuffer_reserve+0x21d/0x347 [i915] [<ffffffffa0080bfb>] ? i915_gem_do_execbuffer.isra.17+0x4f3/0xe61 [i915] [<ffffffffa00795f4>] ? i915_gem_object_get_pages+0x54/0x89 [i915] [<ffffffffa007e405>] ? i915_gem_pwrite_ioctl+0x743/0x7a5 [i915] [<ffffffffa0081a46>] ? i915_gem_execbuffer2+0x15e/0x1e4 [i915] [<ffffffffa000e20d>] ? drm_ioctl+0x2a5/0x3c4 [drm] [<ffffffffa00818e8>] ? i915_gem_execbuffer+0x37f/0x37f [i915] [<ffffffff816f64c0>] ? __do_page_fault+0x3ab/0x449 [<ffffffff810be3da>] ? do_mmap_pgoff+0x2b2/0x341 [<ffffffff810e49be>] ? vfs_ioctl+0x1e/0x31 [<ffffffff810e5194>] ? do_vfs_ioctl+0x3ad/0x3ef [<ffffffff810e5224>] ? SyS_ioctl+0x4e/0x7e [<ffffffff816f88d2>] ? system_call_fastpath+0x16/0x1b Code: 52 0c a0 48 c7 c6 22 30 0d a0 31 c0 e8 ef 00 f9 ff bf c6 a7 00 00 e8 90 5d 24 e1 f6 85 13 01 00 00 10 75 44 48 8b 85 18 01 00 00 <8b> 50 08 48 8b 30 49 8b 84 24 88 02 00 00 48 89 c7 48 81 c7 98 RIP [<ffffffffa0082892>] i915_gem_gtt_finish_object+0x68/0xbd [i915] RSP <ffff880028e4b9e8> CR2: 0000000000000008 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=68171 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@vger.kernel.org [danvet: Bikeshed the comments a bit as discussed with Chris.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c45
1 files changed, 39 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index f21a0c36a40b..d9e337feef14 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1695,6 +1695,7 @@ static long
1695__i915_gem_shrink(struct drm_i915_private *dev_priv, long target, 1695__i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
1696 bool purgeable_only) 1696 bool purgeable_only)
1697{ 1697{
1698 struct list_head still_bound_list;
1698 struct drm_i915_gem_object *obj, *next; 1699 struct drm_i915_gem_object *obj, *next;
1699 long count = 0; 1700 long count = 0;
1700 1701
@@ -1709,23 +1710,55 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
1709 } 1710 }
1710 } 1711 }
1711 1712
1712 list_for_each_entry_safe(obj, next, &dev_priv->mm.bound_list, 1713 /*
1713 global_list) { 1714 * As we may completely rewrite the bound list whilst unbinding
1715 * (due to retiring requests) we have to strictly process only
1716 * one element of the list at the time, and recheck the list
1717 * on every iteration.
1718 */
1719 INIT_LIST_HEAD(&still_bound_list);
1720 while (count < target && !list_empty(&dev_priv->mm.bound_list)) {
1714 struct i915_vma *vma, *v; 1721 struct i915_vma *vma, *v;
1715 1722
1723 obj = list_first_entry(&dev_priv->mm.bound_list,
1724 typeof(*obj), global_list);
1725 list_move_tail(&obj->global_list, &still_bound_list);
1726
1716 if (!i915_gem_object_is_purgeable(obj) && purgeable_only) 1727 if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
1717 continue; 1728 continue;
1718 1729
1730 /*
1731 * Hold a reference whilst we unbind this object, as we may
1732 * end up waiting for and retiring requests. This might
1733 * release the final reference (held by the active list)
1734 * and result in the object being freed from under us.
1735 * in this object being freed.
1736 *
1737 * Note 1: Shrinking the bound list is special since only active
1738 * (and hence bound objects) can contain such limbo objects, so
1739 * we don't need special tricks for shrinking the unbound list.
1740 * The only other place where we have to be careful with active
1741 * objects suddenly disappearing due to retiring requests is the
1742 * eviction code.
1743 *
1744 * Note 2: Even though the bound list doesn't hold a reference
1745 * to the object we can safely grab one here: The final object
1746 * unreferencing and the bound_list are both protected by the
1747 * dev->struct_mutex and so we won't ever be able to observe an
1748 * object on the bound_list with a reference count equals 0.
1749 */
1750 drm_gem_object_reference(&obj->base);
1751
1719 list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link) 1752 list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
1720 if (i915_vma_unbind(vma)) 1753 if (i915_vma_unbind(vma))
1721 break; 1754 break;
1722 1755
1723 if (!i915_gem_object_put_pages(obj)) { 1756 if (i915_gem_object_put_pages(obj) == 0)
1724 count += obj->base.size >> PAGE_SHIFT; 1757 count += obj->base.size >> PAGE_SHIFT;
1725 if (count >= target) 1758
1726 return count; 1759 drm_gem_object_unreference(&obj->base);
1727 }
1728 } 1760 }
1761 list_splice(&still_bound_list, &dev_priv->mm.bound_list);
1729 1762
1730 return count; 1763 return count;
1731} 1764}