summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2019-08-14 22:48:14 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2020-09-03 13:52:05 +0100
commitdd2f172a028903938ef2ebaa9fa506dcec211f20 (patch)
treeef0ef60d3ffcda9ad5f59679e55c242ae69a6cd8
parent792334b3b0b5d9e552b56b6a5bd5fe7c6ae83484 (diff)
i915/gem_userptr_blit: Shoot down a shared mmap_gtt(userptr)
Establish a userptr and inherit it to many children with fresh mm. Into each child mm, mmap_gtt the userptr handle so that they are many different vma in the i_mapping tree pointing back to the userptr. Then proceed to munmap that and force us to revoke all the mmaps. Daniel discovered that from the unmap in the parent, we will call i915_vma_revoke_mmaps() on all the child mappings, which in turn should call mmu_notifier_invalidate_range -- ostensibly recursing from the outer mmu_notifier_invalidate_range of the munamp. v2: Invoke userptr in each child for more mmu-notifiers Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--tests/i915/gem_userptr_blits.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/tests/i915/gem_userptr_blits.c b/tests/i915/gem_userptr_blits.c
index 3ae02201..e46ed047 100644
--- a/tests/i915/gem_userptr_blits.c
+++ b/tests/i915/gem_userptr_blits.c
@@ -1751,6 +1751,89 @@ static void test_unmap(int fd, int expected)
gem_close(fd, bo[i]);
}
+static int count_sigbus(void *ptr, size_t len)
+{
+ struct sigaction sigact, orig_sigact;
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = sigbus;
+ sigact.sa_flags = SA_SIGINFO;
+ igt_assert(sigaction(SIGBUS, &sigact, &orig_sigact) == 0);
+
+ sigbus_start = (unsigned long)ptr;
+ sigbus_cnt = 0;
+ memset(ptr, 0, len);
+
+ sigaction(SIGBUS, &orig_sigact, NULL);
+ return sigbus_cnt;
+}
+
+static void test_unmap_shared(int i915)
+{
+ const int num_child = 64;
+ struct {
+ void *base;
+ uint32_t *gtt;
+ uint32_t bo;
+ } t[2];
+
+ igt_require(gem_has_llc(i915));
+
+ for (int i = 0; i < ARRAY_SIZE(t); i++) {
+ t[i].base = mmap(NULL, sizeof(linear), PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ igt_assert(t[i].base != MAP_FAILED);
+ igt_require(__gem_userptr(i915, t[i].base, sizeof(linear),
+ 0, userptr_flags, &t[i].bo) == 0);
+
+ t[i].gtt = gem_mmap__gtt(i915, t[i].bo,
+ sizeof(linear), PROT_WRITE);
+ *t[i].gtt = i;
+ }
+
+ igt_fork(child, num_child) {
+ uint32_t *ptr;
+
+ /* First attach our own user pointer to prep the mmu notifier */
+ ptr = mmap(NULL, sizeof(linear), PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ igt_assert(ptr != MAP_FAILED);
+ igt_require(__gem_userptr(i915, ptr, sizeof(linear),
+ 0, userptr_flags, ptr) == 0);
+
+ ptr = gem_mmap__gtt(i915, t[0].bo, sizeof(linear), PROT_WRITE);
+ ptr[child] = 1;
+
+ ptr = gem_mmap__gtt(i915, t[1].bo, sizeof(linear), PROT_WRITE);
+ while (READ_ONCE(*ptr) == 1)
+ usleep(10 * 1000);
+
+ ptr = gem_mmap__gtt(i915, t[0].bo, sizeof(linear), PROT_WRITE);
+ igt_assert(count_sigbus(ptr, 1) > 0);
+ }
+
+ /* busy wait for all children to instantiate their mmap */
+ for (int child = 0; child < num_child; child++) {
+ while (READ_ONCE(t[0].gtt[child]) == 0)
+ ;
+ }
+
+ /* shoot it down! */
+ munmap(t[0].base, sizeof(linear));
+
+ /* check our aim was true */
+ igt_assert(count_sigbus(t[0].gtt, 1) > 0);
+
+ *t[1].gtt = 0;
+ igt_waitchildren();
+
+ for (int i = 0; i < ARRAY_SIZE(t); i++) {
+ gem_close(i915, t[i].bo);
+ munmap(t[i].gtt, sizeof(linear));
+ munmap(t[i].base, sizeof(linear));
+ }
+}
+
static void test_unmap_after_close(int fd)
{
char *ptr, *bo_ptr;
@@ -2281,6 +2364,9 @@ igt_main_args("c:", NULL, help_str, opt_handler, NULL)
igt_subtest("sync-unmap-after-close")
test_unmap_after_close(fd);
+ igt_subtest("sync-unmap-shared")
+ test_unmap_shared(fd);
+
igt_subtest("stress-mm")
test_stress_mm(fd, 5);
igt_subtest("stress-purge")