diff options
Diffstat (limited to 'tools/testing')
| -rw-r--r-- | tools/testing/selftests/vm/hmm-tests.c | 49 | ||||
| -rw-r--r-- | tools/testing/selftests/vm/userfaultfd.c | 22 | 
2 files changed, 70 insertions, 1 deletions
diff --git a/tools/testing/selftests/vm/hmm-tests.c b/tools/testing/selftests/vm/hmm-tests.c index 7d722265dcd7..4adaad1b822f 100644 --- a/tools/testing/selftests/vm/hmm-tests.c +++ b/tools/testing/selftests/vm/hmm-tests.c @@ -1054,6 +1054,55 @@ TEST_F(hmm, migrate_fault)  	hmm_buffer_free(buffer);  } +TEST_F(hmm, migrate_release) +{ +	struct hmm_buffer *buffer; +	unsigned long npages; +	unsigned long size; +	unsigned long i; +	int *ptr; +	int ret; + +	npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; +	ASSERT_NE(npages, 0); +	size = npages << self->page_shift; + +	buffer = malloc(sizeof(*buffer)); +	ASSERT_NE(buffer, NULL); + +	buffer->fd = -1; +	buffer->size = size; +	buffer->mirror = malloc(size); +	ASSERT_NE(buffer->mirror, NULL); + +	buffer->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, +			   MAP_PRIVATE | MAP_ANONYMOUS, buffer->fd, 0); +	ASSERT_NE(buffer->ptr, MAP_FAILED); + +	/* Initialize buffer in system memory. */ +	for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) +		ptr[i] = i; + +	/* Migrate memory to device. */ +	ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages); +	ASSERT_EQ(ret, 0); +	ASSERT_EQ(buffer->cpages, npages); + +	/* Check what the device read. */ +	for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) +		ASSERT_EQ(ptr[i], i); + +	/* Release device memory. */ +	ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_RELEASE, buffer, npages); +	ASSERT_EQ(ret, 0); + +	/* Fault pages back to system memory and check them. */ +	for (i = 0, ptr = buffer->ptr; i < size / (2 * sizeof(*ptr)); ++i) +		ASSERT_EQ(ptr[i], i); + +	hmm_buffer_free(buffer); +} +  /*   * Migrate anonymous shared memory to device private memory.   */ diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index 74babdbc02e5..297f250c1d95 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -774,7 +774,27 @@ static void uffd_handle_page_fault(struct uffd_msg *msg,  		continue_range(uffd, msg->arg.pagefault.address, page_size);  		stats->minor_faults++;  	} else { -		/* Missing page faults */ +		/* +		 * Missing page faults. +		 * +		 * Here we force a write check for each of the missing mode +		 * faults.  It's guaranteed because the only threads that +		 * will trigger uffd faults are the locking threads, and +		 * their first instruction to touch the missing page will +		 * always be pthread_mutex_lock(). +		 * +		 * Note that here we relied on an NPTL glibc impl detail to +		 * always read the lock type at the entry of the lock op +		 * (pthread_mutex_t.__data.__type, offset 0x10) before +		 * doing any locking operations to guarantee that.  It's +		 * actually not good to rely on this impl detail because +		 * logically a pthread-compatible lib can implement the +		 * locks without types and we can fail when linking with +		 * them.  However since we used to find bugs with this +		 * strict check we still keep it around.  Hopefully this +		 * could be a good hint when it fails again.  If one day +		 * it'll break on some other impl of glibc we'll revisit. +		 */  		if (msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE)  			err("unexpected write fault");  | 
