[PATCH] userfaultfd: selftest: make supported range ioctl verification more robust

From: Mike Rapoport
Date: Tue Aug 07 2018 - 02:44:19 EST


When userfaultfd tests runs on older kernel that does not support
UFFDIO_ZEROPAGE for shared memory it fails at the ioctl verification.

Split out the verification that supported ioctls are superset of the
expected ioctls and relax the checks for UFFDIO_ZEROPAGE for shared memory
areas.

Signed-off-by: Mike Rapoport <rppt@xxxxxxxxxxxxxxxxxx>
---
tools/testing/selftests/vm/userfaultfd.c | 63 +++++++++++++++++---------------
1 file changed, 34 insertions(+), 29 deletions(-)

diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
index 7b8171e3128a..a64bc38bc0e1 100644
--- a/tools/testing/selftests/vm/userfaultfd.c
+++ b/tools/testing/selftests/vm/userfaultfd.c
@@ -271,6 +271,32 @@ static int my_bcmp(char *str1, char *str2, size_t n)
return 0;
}

+static int verify_ioctls(unsigned long supported_ioctls)
+{
+ unsigned long expected_ioctls = uffd_test_ops->expected_ioctls;
+
+ if ((supported_ioctls & expected_ioctls) == expected_ioctls)
+ return 0;
+
+ /*
+ * For older kernels shared memory may not have UFFDIO_ZEROPAGE.
+ * In this case we just mask it out from the
+ * expected_ioctls. The userfaultfd_zeropage_test will then
+ * verify that an attempt to use UFFDIO_ZEROPAGE returns
+ * EINVAL
+ */
+ if (test_type == TEST_SHMEM) {
+ expected_ioctls &= ~(1 << _UFFDIO_ZEROPAGE);
+ if ((supported_ioctls & expected_ioctls) == expected_ioctls) {
+ uffd_test_ops->expected_ioctls = expected_ioctls;
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "unexpected missing ioctl\n");
+ return 1;
+}
+
static void *locking_thread(void *arg)
{
unsigned long cpu = (unsigned long) arg;
@@ -851,7 +877,6 @@ static int uffdio_zeropage(int ufd, unsigned long offset)
static int userfaultfd_zeropage_test(void)
{
struct uffdio_register uffdio_register;
- unsigned long expected_ioctls;

printf("testing UFFDIO_ZEROPAGE: ");
fflush(stdout);
@@ -867,12 +892,8 @@ static int userfaultfd_zeropage_test(void)
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
fprintf(stderr, "register failure\n"), exit(1);

- expected_ioctls = uffd_test_ops->expected_ioctls;
- if ((uffdio_register.ioctls & expected_ioctls) !=
- expected_ioctls)
- fprintf(stderr,
- "unexpected missing ioctl for anon memory\n"),
- exit(1);
+ if (verify_ioctls(uffdio_register.ioctls))
+ return 1;

if (uffdio_zeropage(uffd, 0)) {
if (my_bcmp(area_dst, zeropage, page_size))
@@ -887,7 +908,6 @@ static int userfaultfd_zeropage_test(void)
static int userfaultfd_events_test(void)
{
struct uffdio_register uffdio_register;
- unsigned long expected_ioctls;
unsigned long userfaults;
pthread_t uffd_mon;
int err, features;
@@ -912,12 +932,8 @@ static int userfaultfd_events_test(void)
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
fprintf(stderr, "register failure\n"), exit(1);

- expected_ioctls = uffd_test_ops->expected_ioctls;
- if ((uffdio_register.ioctls & expected_ioctls) !=
- expected_ioctls)
- fprintf(stderr,
- "unexpected missing ioctl for anon memory\n"),
- exit(1);
+ if (verify_ioctls(uffdio_register.ioctls))
+ return 1;

if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL))
perror("uffd_poll_thread create"), exit(1);
@@ -947,7 +963,6 @@ static int userfaultfd_events_test(void)
static int userfaultfd_sig_test(void)
{
struct uffdio_register uffdio_register;
- unsigned long expected_ioctls;
unsigned long userfaults;
pthread_t uffd_mon;
int err, features;
@@ -971,12 +986,8 @@ static int userfaultfd_sig_test(void)
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
fprintf(stderr, "register failure\n"), exit(1);

- expected_ioctls = uffd_test_ops->expected_ioctls;
- if ((uffdio_register.ioctls & expected_ioctls) !=
- expected_ioctls)
- fprintf(stderr,
- "unexpected missing ioctl for anon memory\n"),
- exit(1);
+ if (verify_ioctls(uffdio_register.ioctls))
+ return 1;

if (faulting_process(1))
fprintf(stderr, "faulting process failed\n"), exit(1);
@@ -1076,8 +1087,6 @@ static int userfaultfd_stress(void)

err = 0;
while (bounces--) {
- unsigned long expected_ioctls;
-
printf("bounces: %d, mode:", bounces);
if (bounces & BOUNCE_RANDOM)
printf(" rnd");
@@ -1103,13 +1112,9 @@ static int userfaultfd_stress(void)
fprintf(stderr, "register failure\n");
return 1;
}
- expected_ioctls = uffd_test_ops->expected_ioctls;
- if ((uffdio_register.ioctls & expected_ioctls) !=
- expected_ioctls) {
- fprintf(stderr,
- "unexpected missing ioctl for anon memory\n");
+
+ if (verify_ioctls(uffdio_register.ioctls))
return 1;
- }

if (area_dst_alias) {
uffdio_register.range.start = (unsigned long)
--
2.7.4


> Also change userfaultfd_events_test() and userfaultfd_stress() to ignore
> the missing UFFDIO_ZEROPAGE bit from the list of supported ioctls since
> these tests don't require that feature.
>
> Signed-off-by: Thiago Jung Bauermann <bauerman@xxxxxxxxxxxxx>
> ---
> tools/testing/selftests/vm/userfaultfd.c | 36 +++++++++++++++++++++++++++-----
> 1 file changed, 31 insertions(+), 5 deletions(-)
>
> diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
> index c84e44ddf314..00f1ca663d67 100644
> --- a/tools/testing/selftests/vm/userfaultfd.c
> +++ b/tools/testing/selftests/vm/userfaultfd.c
> @@ -852,6 +852,16 @@ static int uffdio_zeropage(int ufd, unsigned long offset)
> return __uffdio_zeropage(ufd, offset, false);
> }
>
> +/* Tells whether the kernel doesn't support ZEROPAGE on shared memory VMAs. */
> +static bool shmem_without_zeropage_support(unsigned long expected_ioctls,
> + unsigned long supported_ioctls)
> +{
> + /* Turn off ZEROPAGE bit from expected_ioctls. */
> + expected_ioctls &= ~(1 << _UFFDIO_ZEROPAGE);
> +
> + return test_type == TEST_SHMEM && supported_ioctls == expected_ioctls;
> +}
> +
> /* exercise UFFDIO_ZEROPAGE */
> static int userfaultfd_zeropage_test(void)
> {
> @@ -877,10 +887,20 @@ static int userfaultfd_zeropage_test(void)
>
> expected_ioctls = uffd_test_ops->expected_ioctls;
> if ((uffdio_register.ioctls & expected_ioctls) !=
> - expected_ioctls)
> + expected_ioctls) {
> + close(uffd);
> +
> + if (shmem_without_zeropage_support(expected_ioctls,
> + uffdio_register.ioctls)) {
> + fprintf(stderr,
> + "UFFDIO_ZEROPAGE unsupported in shmem VMAs\n");
> + return KSFT_SKIP;
> + }
> +
> fprintf(stderr,
> - "unexpected missing ioctl for anon memory\n"),
> - exit(1);
> + "unexpected missing ioctl for anon memory\n");
> + return 1;
> + }
>
> if (uffdio_zeropage(uffd, 0)) {
> if (my_bcmp(area_dst, zeropage, page_size))
> @@ -924,7 +944,10 @@ static int userfaultfd_events_test(void)
>
> expected_ioctls = uffd_test_ops->expected_ioctls;
> if ((uffdio_register.ioctls & expected_ioctls) !=
> - expected_ioctls)
> + expected_ioctls &&
> + /* No need for zeropage support in this test, so ignore it. */
> + !shmem_without_zeropage_support(expected_ioctls,
> + uffdio_register.ioctls))
> fprintf(stderr,
> "unexpected missing ioctl for anon memory\n"),
> exit(1);
> @@ -1117,7 +1140,10 @@ static int userfaultfd_stress(void)
> }
> expected_ioctls = uffd_test_ops->expected_ioctls;
> if ((uffdio_register.ioctls & expected_ioctls) !=
> - expected_ioctls) {
> + expected_ioctls &&
> + /* No need for zeropage support in this test, so ignore it. */
> + !shmem_without_zeropage_support(expected_ioctls,
> + uffdio_register.ioctls)) {
> fprintf(stderr,
> "unexpected missing ioctl for anon memory\n");
> return 1;

--
Sincerely yours,
Mike.