summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichał Winiarski <michal.winiarski@intel.com>2015-06-30 17:01:10 +0200
committerChris Wilson <chris@chris-wilson.co.uk>2017-03-08 21:57:09 +0000
commit7b46ae1ba16082669dc7947b290e327a86b68afa (patch)
tree93a1e4f1c23fc91baf1a40eaba46e0c0ca179b18
parentfd9f3647bb4a5ead4c2e55c3cf04bd5364486c6a (diff)
tests/gem_userptr_blits: subtests for MAP_FIXED mappings of regular BO
When the memory backing the userptr object is released by the user, but the BO itself is not closed, it's possible to trigger recursive deadlock caused by operations done on different BO mapped in that region. Testcases are simulating such behaviour by using MAP_FIXED mmap flag. Signed-off-by: Michał Winiarski <michal.winiarski@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
-rw-r--r--lib/ioctl_wrappers.c33
-rw-r--r--lib/ioctl_wrappers.h4
-rw-r--r--tests/gem_userptr_blits.c77
3 files changed, 100 insertions, 14 deletions
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
index 32cb0f36..4d30443f 100644
--- a/lib/ioctl_wrappers.c
+++ b/lib/ioctl_wrappers.c
@@ -403,29 +403,38 @@ void gem_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t leng
igt_assert_eq(__gem_read(fd, handle, offset, buf, length), 0);
}
+int __gem_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write)
+{
+ struct drm_i915_gem_set_domain set_domain;
+ int err;
+
+ memset(&set_domain, 0, sizeof(set_domain));
+ set_domain.handle = handle;
+ set_domain.read_domains = read;
+ set_domain.write_domain = write;
+
+ err = 0;
+ if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain))
+ err = -errno;
+
+ return err;
+}
+
/**
* gem_set_domain:
* @fd: open i915 drm file descriptor
* @handle: gem buffer object handle
- * @read_domains: gem domain bits for read access
- * @write_domain: gem domain bit for write access
+ * @read: gem domain bits for read access
+ * @write: gem domain bit for write access
*
* This wraps the SET_DOMAIN ioctl, which is used to control the coherency of
* the gem buffer object between the cpu and gtt mappings. It is also use to
* synchronize with outstanding rendering in general, but for that use-case
* please have a look at gem_sync().
*/
-void gem_set_domain(int fd, uint32_t handle,
- uint32_t read_domains, uint32_t write_domain)
+void gem_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write)
{
- struct drm_i915_gem_set_domain set_domain;
-
- memset(&set_domain, 0, sizeof(set_domain));
- set_domain.handle = handle;
- set_domain.read_domains = read_domains;
- set_domain.write_domain = write_domain;
-
- do_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
+ igt_assert_eq(__gem_set_domain(fd, handle, read, write), 0);
}
/**
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index af061ef3..56c5d14c 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -65,8 +65,8 @@ void gem_close(int fd, uint32_t handle);
int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length);
void gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length);
void gem_read(int fd, uint32_t handle, uint64_t offset, void *buf, uint64_t length);
-void gem_set_domain(int fd, uint32_t handle,
- uint32_t read_domains, uint32_t write_domain);
+int __gem_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write);
+void gem_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write);
int gem_wait(int fd, uint32_t handle, int64_t *timeout_ns);
void gem_sync(int fd, uint32_t handle);
bool gem_create__has_stolen_support(int fd);
diff --git a/tests/gem_userptr_blits.c b/tests/gem_userptr_blits.c
index 0df53105..49a7f2f4 100644
--- a/tests/gem_userptr_blits.c
+++ b/tests/gem_userptr_blits.c
@@ -614,6 +614,74 @@ static void test_forked_access(int fd)
free(ptr2);
}
+#define MAP_FIXED_INVALIDATE_OVERLAP (1<<0)
+#define MAP_FIXED_INVALIDATE_BUSY (1<<1)
+#define MAP_FIXED_INVALIDATE_GET_PAGES (1<<2)
+#define ALL_MAP_FIXED_INVALIDATE (MAP_FIXED_INVALIDATE_OVERLAP | \
+ MAP_FIXED_INVALIDATE_BUSY | \
+ MAP_FIXED_INVALIDATE_GET_PAGES)
+
+static int test_map_fixed_invalidate(int fd, uint32_t flags)
+{
+ const size_t ptr_size = sizeof(linear) + 2*PAGE_SIZE;
+ const int num_handles = (flags & MAP_FIXED_INVALIDATE_OVERLAP) ? 2 : 1;
+ uint32_t handle[num_handles];
+ uint32_t *ptr;
+
+ ptr = mmap(NULL, ptr_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS,
+ -1, 0);
+ igt_assert(ptr != MAP_FAILED);
+
+ for (int i = 0; i < num_handles; i++)
+ handle[i] = create_userptr(fd, 0, ptr + PAGE_SIZE/sizeof(*ptr));
+
+ for (char *fixed = (char *)ptr, *end = fixed + ptr_size;
+ fixed + 2*PAGE_SIZE <= end;
+ fixed += PAGE_SIZE) {
+ struct drm_i915_gem_mmap_gtt mmap_gtt;
+ char *map;
+
+ ptr = mmap(ptr, ptr_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED,
+ -1, 0);
+
+ memset(&mmap_gtt, 0, sizeof(mmap_gtt));
+ mmap_gtt.handle = gem_create(fd, 2*PAGE_SIZE);
+ do_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_gtt);
+
+ if (flags & MAP_FIXED_INVALIDATE_BUSY)
+ copy(fd, handle[0], handle[num_handles-1], 0);
+
+ map = mmap(fixed, 2*PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED,
+ fd, mmap_gtt.offset);
+ igt_assert(map == fixed);
+
+ gem_set_tiling(fd, mmap_gtt.handle, I915_TILING_NONE, 0);
+ *(uint32_t*)map = 0xdead;
+
+ if (flags & MAP_FIXED_INVALIDATE_GET_PAGES)
+ igt_assert_eq(__gem_set_domain(fd, handle[0],
+ I915_GEM_DOMAIN_GTT,
+ I915_GEM_DOMAIN_GTT),
+ -EFAULT);
+
+ gem_set_tiling(fd, mmap_gtt.handle, I915_TILING_Y, 512 * 4);
+ *(uint32_t*)map = 0xbeef;
+
+ gem_close(fd, mmap_gtt.handle);
+ }
+
+ for (int i = 0; i < num_handles; i++)
+ gem_close(fd, handle[i]);
+ munmap(ptr, ptr_size);
+
+ return 0;
+}
+
static int test_forbidden_ops(int fd)
{
struct drm_i915_gem_pread gem_pread;
@@ -1504,6 +1572,15 @@ int main(int argc, char **argv)
igt_subtest("stress-mm-invalidate-close-overlap")
test_invalidate_close_race(fd, true);
+ for (unsigned flags = 0; flags < ALL_MAP_FIXED_INVALIDATE + 1; flags++) {
+ igt_subtest_f("map-fixed-invalidate%s%s%s",
+ flags & MAP_FIXED_INVALIDATE_OVERLAP ? "-overlap" : "",
+ flags & MAP_FIXED_INVALIDATE_BUSY ? "-busy" : "",
+ flags & MAP_FIXED_INVALIDATE_GET_PAGES ? "-gup" : "") {
+ test_map_fixed_invalidate(fd, flags);
+ }
+ }
+
igt_subtest("coherency-sync")
test_coherency(fd, count);