summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-06-18 20:02:52 +0000
committerkib <kib@FreeBSD.org>2013-06-18 20:02:52 +0000
commitfe5306317669ed47de0598495c4733a9e70c4ec4 (patch)
treea1b400f9e301719df24bff7525466d9caf266abf
parent136a667b922ca135b2d19325a0394a275961bfad (diff)
downloadFreeBSD-src-fe5306317669ed47de0598495c4733a9e70c4ec4.zip
FreeBSD-src-fe5306317669ed47de0598495c4733a9e70c4ec4.tar.gz
Since the gem pagefault handler relocks the vm object lock, other
thread might fault on the same GTT offset meantime and instantiate the mapping. Recheck that the mgt device object still does not have a page at the current offset after relocking, and return a possibly installed page. Reported by: Oleg Sidorkin <osidorkin@gmail.com> Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
-rw-r--r--sys/dev/drm2/i915/i915_gem.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c
index d655055..c505cdb 100644
--- a/sys/dev/drm2/i915/i915_gem.c
+++ b/sys/dev/drm2/i915/i915_gem.c
@@ -1371,6 +1371,23 @@ unlocked_vmobj:
} else
DRM_LOCK(dev);
+ /*
+ * Since the object lock was dropped, other thread might have
+ * faulted on the same GTT address and instantiated the
+ * mapping for the page. Recheck.
+ */
+ VM_OBJECT_WLOCK(vm_obj);
+ m = vm_page_lookup(vm_obj, OFF_TO_IDX(offset));
+ if (m != NULL) {
+ if ((m->flags & VPO_BUSY) != 0) {
+ DRM_UNLOCK(dev);
+ vm_page_sleep(m, "915pee");
+ goto retry;
+ }
+ goto have_page;
+ } else
+ VM_OBJECT_WUNLOCK(vm_obj);
+
/* Now bind it into the GTT if needed */
if (!obj->map_and_fenceable) {
ret = i915_gem_object_unbind(obj);
@@ -1424,8 +1441,9 @@ unlocked_vmobj:
goto retry;
}
m->valid = VM_PAGE_BITS_ALL;
- *mres = m;
vm_page_insert(m, vm_obj, OFF_TO_IDX(offset));
+have_page:
+ *mres = m;
vm_page_busy(m);
CTR4(KTR_DRM, "fault %p %jx %x phys %x", gem_obj, offset, prot,
OpenPOWER on IntegriCloud