diff options
Diffstat (limited to 'tools/testing/selftests/mm/uffd-unit-tests.c')
| -rw-r--r-- | tools/testing/selftests/mm/uffd-unit-tests.c | 109 | 
1 files changed, 108 insertions, 1 deletions
diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c index 6857388783be..bb492c258486 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -9,9 +9,116 @@  #ifdef __NR_userfaultfd +static void uffd_test_report(void) +{ +	printf("Userfaults unit tests: pass=%u, skip=%u, fail=%u (total=%u)\n", +	       ksft_get_pass_cnt(), +	       ksft_get_xskip_cnt(), +	       ksft_get_fail_cnt(), +	       ksft_test_num()); +} + +static void uffd_test_pass(void) +{ +	printf("done\n"); +	ksft_inc_pass_cnt(); +} + +#define  uffd_test_start(...)  do {		\ +		printf("Testing ");		\ +		printf(__VA_ARGS__);		\ +		printf("... ");			\ +		fflush(stdout);			\ +	} while (0) + +#define  uffd_test_fail(...)  do {		\ +		printf("failed [reason: ");	\ +		printf(__VA_ARGS__);		\ +		printf("]\n");			\ +		ksft_inc_fail_cnt();		\ +	} while (0) + +#define  uffd_test_skip(...)  do {		\ +		printf("skipped [reason: ");	\ +		printf(__VA_ARGS__);		\ +		printf("]\n");			\ +		ksft_inc_xskip_cnt();		\ +	} while (0) + +/* + * Returns 1 if specific userfaultfd supported, 0 otherwise.  Note, we'll + * return 1 even if some test failed as long as uffd supported, because in + * that case we still want to proceed with the rest uffd unit tests. + */ +static int test_uffd_api(bool use_dev) +{ +	struct uffdio_api uffdio_api; +	int uffd; + +	uffd_test_start("UFFDIO_API (with %s)", +			use_dev ? "/dev/userfaultfd" : "syscall"); + +	if (use_dev) +		uffd = uffd_open_dev(UFFD_FLAGS); +	else +		uffd = uffd_open_sys(UFFD_FLAGS); +	if (uffd < 0) { +		uffd_test_skip("cannot open userfaultfd handle"); +		return 0; +	} + +	/* Test wrong UFFD_API */ +	uffdio_api.api = 0xab; +	uffdio_api.features = 0; +	if (ioctl(uffd, UFFDIO_API, &uffdio_api) == 0) { +		uffd_test_fail("UFFDIO_API should fail with wrong api but didn't"); +		goto out; +	} + +	/* Test wrong feature bit */ +	uffdio_api.api = UFFD_API; +	uffdio_api.features = BIT_ULL(63); +	if (ioctl(uffd, UFFDIO_API, &uffdio_api) == 0) { +		uffd_test_fail("UFFDIO_API should fail with wrong feature but didn't"); +		goto out; +	} + +	/* Test normal UFFDIO_API */ +	uffdio_api.api = UFFD_API; +	uffdio_api.features = 0; +	if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { +		uffd_test_fail("UFFDIO_API should succeed but failed"); +		goto out; +	} + +	/* Test double requests of UFFDIO_API with a random feature set */ +	uffdio_api.features = BIT_ULL(0); +	if (ioctl(uffd, UFFDIO_API, &uffdio_api) == 0) { +		uffd_test_fail("UFFDIO_API should reject initialized uffd"); +		goto out; +	} + +	uffd_test_pass(); +out: +	close(uffd); +	/* We have a valid uffd handle */ +	return 1; +} +  int main(int argc, char *argv[])  { -	return KSFT_PASS; +	int has_uffd; + +	has_uffd = test_uffd_api(false); +	has_uffd |= test_uffd_api(true); + +	if (!has_uffd) { +		printf("Userfaultfd not supported or unprivileged, skip all tests\n"); +		exit(KSFT_SKIP); +	} +	uffd_test_report(); + +	return ksft_get_fail_cnt() ? KSFT_FAIL : KSFT_PASS;  }  #else /* __NR_userfaultfd */  |