diff options
author | Michał Winiarski <michal.winiarski@intel.com> | 2015-06-30 17:01:10 +0200 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2017-03-08 21:57:09 +0000 |
commit | 7b46ae1ba16082669dc7947b290e327a86b68afa (patch) | |
tree | 93a1e4f1c23fc91baf1a40eaba46e0c0ca179b18 | |
parent | fd9f3647bb4a5ead4c2e55c3cf04bd5364486c6a (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.c | 33 | ||||
-rw-r--r-- | lib/ioctl_wrappers.h | 4 | ||||
-rw-r--r-- | tests/gem_userptr_blits.c | 77 |
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); |