diff mbox series

[v2,5/6] userfaultfd: selftests: make /dev/userfaultfd testing configurable

Message ID 20220422212945.2227722-6-axelrasmussen@google.com (mailing list archive)
State New, archived
Headers show
Series userfaultfd: add /dev/userfaultfd for fine grained access control | expand

Commit Message

Axel Rasmussen April 22, 2022, 9:29 p.m. UTC
Instead of always testing both userfaultfd(2) and /dev/userfaultfd,
let the user choose which to test.

As with other test features, change the behavior based on a new
command line flag. Introduce the idea of "test mods", which are
generic (not specific to a test type) modifications to the behavior of
the test. This is sort of borrowed from this RFC patch series [1], but
simplified a bit.

The benefit is, in "typical" configurations this test is somewhat slow
(say, 30sec or something). Testing both clearly doubles it, so it may
not always be desirable, as users are likely to use one or the other,
but never both, in the "real world".

[1]: https://patchwork.kernel.org/project/linux-mm/patch/20201129004548.1619714-14-namit@vmware.com/

Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
---
 tools/testing/selftests/vm/userfaultfd.c | 41 +++++++++++++++++-------
 1 file changed, 30 insertions(+), 11 deletions(-)

Comments

Shuah Khan April 26, 2022, 4:56 p.m. UTC | #1
On 4/22/22 3:29 PM, Axel Rasmussen wrote:
> Instead of always testing both userfaultfd(2) and /dev/userfaultfd,
> let the user choose which to test.
> 
> As with other test features, change the behavior based on a new
> command line flag. Introduce the idea of "test mods", which are
> generic (not specific to a test type) modifications to the behavior of
> the test. This is sort of borrowed from this RFC patch series [1], but
> simplified a bit.
> 
> The benefit is, in "typical" configurations this test is somewhat slow
> (say, 30sec or something). Testing both clearly doubles it, so it may
> not always be desirable, as users are likely to use one or the other,
> but never both, in the "real world".
> 
> [1]: https://patchwork.kernel.org/project/linux-mm/patch/20201129004548.1619714-14-namit@vmware.com/
> 
> Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
> ---
>   tools/testing/selftests/vm/userfaultfd.c | 41 +++++++++++++++++-------
>   1 file changed, 30 insertions(+), 11 deletions(-)
> 
> diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
> index 12ae742a9981..274522704e40 100644
> --- a/tools/testing/selftests/vm/userfaultfd.c
> +++ b/tools/testing/selftests/vm/userfaultfd.c
> @@ -142,8 +142,17 @@ static void usage(void)
>   {
>   	fprintf(stderr, "\nUsage: ./userfaultfd <test type> <MiB> <bounces> "
>   		"[hugetlbfs_file]\n\n");
> +

Remove the extra blank line here.

>   	fprintf(stderr, "Supported <test type>: anon, hugetlb, "
>   		"hugetlb_shared, shmem\n\n");
> +

Remove the extra blank line here.

> +	fprintf(stderr, "'Test mods' can be joined to the test type string with a ':'. "
> +		"Supported mods:\n");
> +	fprintf(stderr, "\tdev - Use /dev/userfaultfd instead of userfaultfd(2)\n");
> +	fprintf(stderr, "\nExample test mod usage:\n");
> +	fprintf(stderr, "# Run anonymous memory test with /dev/userfaultfd:\n");
> +	fprintf(stderr, "./userfaultfd anon:dev 100 99999\n\n");
> +
>   	fprintf(stderr, "Examples:\n\n");
>   	fprintf(stderr, "%s", examples);

Update examples above with new test cases if any.

>   	exit(1);
> @@ -1610,8 +1619,6 @@ unsigned long default_huge_page_size(void)
>   
>   static void set_test_type(const char *type)
>   {
> -	uint64_t features = UFFD_API_FEATURES;
> -
>   	if (!strcmp(type, "anon")) {
>   		test_type = TEST_ANON;
>   		uffd_test_ops = &anon_uffd_test_ops;
> @@ -1631,10 +1638,28 @@ static void set_test_type(const char *type)
>   		test_type = TEST_SHMEM;
>   		uffd_test_ops = &shmem_uffd_test_ops;
>   		test_uffdio_minor = true;
> -	} else {
> -		err("Unknown test type: %s", type);
> +	}

At this point, it might make it so much easier and maintainable if
we were to use getopt instead of parsing options.

> +}
> +
> +static void parse_test_type_arg(const char *raw_type)
> +{
> +	char *buf = strdup(raw_type);
> +	uint64_t features = UFFD_API_FEATURES;
> +
> +	while (buf) {
> +		const char *token = strsep(&buf, ":");
> +
> +		if (!test_type)
> +			set_test_type(token);
> +		else if (!strcmp(token, "dev"))
> +			test_dev_userfaultfd = true;
> +		else
> +			err("unrecognized test mod '%s'", token);
>   	}
>   
> +	if (!test_type)
> +		err("failed to parse test type argument: '%s'", raw_type);
> +
>   	if (test_type == TEST_HUGETLB)
>   		page_size = default_huge_page_size();
>   	else
> @@ -1681,7 +1706,7 @@ int main(int argc, char **argv)
>   		err("failed to arm SIGALRM");
>   	alarm(ALARM_INTERVAL_SECS);
>   
> -	set_test_type(argv[1]);
> +	parse_test_type_arg(argv[1]);
>   
>   	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
>   	nr_pages_per_cpu = atol(argv[2]) * 1024*1024 / page_size /
> @@ -1719,12 +1744,6 @@ int main(int argc, char **argv)
>   	}
>   	printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
>   	       nr_pages, nr_pages_per_cpu);
> -
> -	test_dev_userfaultfd = false;
> -	if (userfaultfd_stress())
> -		return 1;
> -
> -	test_dev_userfaultfd = true;
>   	return userfaultfd_stress();
>   }
>   
> 

Same comments as before on fail vs. skip conditions to watch out
for and report them correctly.

thanks,
-- Shuah
Axel Rasmussen May 19, 2022, 7:13 p.m. UTC | #2
On Tue, Apr 26, 2022 at 9:56 AM Shuah Khan <skhan@linuxfoundation.org> wrote:
>
> On 4/22/22 3:29 PM, Axel Rasmussen wrote:
> > Instead of always testing both userfaultfd(2) and /dev/userfaultfd,
> > let the user choose which to test.
> >
> > As with other test features, change the behavior based on a new
> > command line flag. Introduce the idea of "test mods", which are
> > generic (not specific to a test type) modifications to the behavior of
> > the test. This is sort of borrowed from this RFC patch series [1], but
> > simplified a bit.
> >
> > The benefit is, in "typical" configurations this test is somewhat slow
> > (say, 30sec or something). Testing both clearly doubles it, so it may
> > not always be desirable, as users are likely to use one or the other,
> > but never both, in the "real world".
> >
> > [1]: https://patchwork.kernel.org/project/linux-mm/patch/20201129004548.1619714-14-namit@vmware.com/
> >
> > Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
> > ---
> >   tools/testing/selftests/vm/userfaultfd.c | 41 +++++++++++++++++-------
> >   1 file changed, 30 insertions(+), 11 deletions(-)
> >
> > diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
> > index 12ae742a9981..274522704e40 100644
> > --- a/tools/testing/selftests/vm/userfaultfd.c
> > +++ b/tools/testing/selftests/vm/userfaultfd.c
> > @@ -142,8 +142,17 @@ static void usage(void)
> >   {
> >       fprintf(stderr, "\nUsage: ./userfaultfd <test type> <MiB> <bounces> "
> >               "[hugetlbfs_file]\n\n");
> > +
>
> Remove the extra blank line here.
>
> >       fprintf(stderr, "Supported <test type>: anon, hugetlb, "
> >               "hugetlb_shared, shmem\n\n");
> > +
>
> Remove the extra blank line here.
>
> > +     fprintf(stderr, "'Test mods' can be joined to the test type string with a ':'. "
> > +             "Supported mods:\n");
> > +     fprintf(stderr, "\tdev - Use /dev/userfaultfd instead of userfaultfd(2)\n");
> > +     fprintf(stderr, "\nExample test mod usage:\n");
> > +     fprintf(stderr, "# Run anonymous memory test with /dev/userfaultfd:\n");
> > +     fprintf(stderr, "./userfaultfd anon:dev 100 99999\n\n");
> > +
> >       fprintf(stderr, "Examples:\n\n");
> >       fprintf(stderr, "%s", examples);
>
> Update examples above with new test cases if any.

Will fix the above comments in v3.

>
> >       exit(1);
> > @@ -1610,8 +1619,6 @@ unsigned long default_huge_page_size(void)
> >
> >   static void set_test_type(const char *type)
> >   {
> > -     uint64_t features = UFFD_API_FEATURES;
> > -
> >       if (!strcmp(type, "anon")) {
> >               test_type = TEST_ANON;
> >               uffd_test_ops = &anon_uffd_test_ops;
> > @@ -1631,10 +1638,28 @@ static void set_test_type(const char *type)
> >               test_type = TEST_SHMEM;
> >               uffd_test_ops = &shmem_uffd_test_ops;
> >               test_uffdio_minor = true;
> > -     } else {
> > -             err("Unknown test type: %s", type);
> > +     }
>
> At this point, it might make it so much easier and maintainable if
> we were to use getopt instead of parsing options.

Agreed, I'd like that as well. But, since it's a bigger refactor that
affects all test types, I think it may be cleaner to leave it for a
follow-up series.

>
> > +}
> > +
> > +static void parse_test_type_arg(const char *raw_type)
> > +{
> > +     char *buf = strdup(raw_type);
> > +     uint64_t features = UFFD_API_FEATURES;
> > +
> > +     while (buf) {
> > +             const char *token = strsep(&buf, ":");
> > +
> > +             if (!test_type)
> > +                     set_test_type(token);
> > +             else if (!strcmp(token, "dev"))
> > +                     test_dev_userfaultfd = true;
> > +             else
> > +                     err("unrecognized test mod '%s'", token);
> >       }
> >
> > +     if (!test_type)
> > +             err("failed to parse test type argument: '%s'", raw_type);
> > +
> >       if (test_type == TEST_HUGETLB)
> >               page_size = default_huge_page_size();
> >       else
> > @@ -1681,7 +1706,7 @@ int main(int argc, char **argv)
> >               err("failed to arm SIGALRM");
> >       alarm(ALARM_INTERVAL_SECS);
> >
> > -     set_test_type(argv[1]);
> > +     parse_test_type_arg(argv[1]);
> >
> >       nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
> >       nr_pages_per_cpu = atol(argv[2]) * 1024*1024 / page_size /
> > @@ -1719,12 +1744,6 @@ int main(int argc, char **argv)
> >       }
> >       printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
> >              nr_pages, nr_pages_per_cpu);
> > -
> > -     test_dev_userfaultfd = false;
> > -     if (userfaultfd_stress())
> > -             return 1;
> > -
> > -     test_dev_userfaultfd = true;
> >       return userfaultfd_stress();
> >   }
> >
> >
>
> Same comments as before on fail vs. skip conditions to watch out
> for and report them correctly.

I think in v3 things will be correct. Basically, in the skip cases we
just exit(KSFT_SKIP) directly, instead of relying on the return value
here. I'll take a pass and double check though before sending v3.

>
> thanks,
> -- Shuah
>
diff mbox series

Patch

diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
index 12ae742a9981..274522704e40 100644
--- a/tools/testing/selftests/vm/userfaultfd.c
+++ b/tools/testing/selftests/vm/userfaultfd.c
@@ -142,8 +142,17 @@  static void usage(void)
 {
 	fprintf(stderr, "\nUsage: ./userfaultfd <test type> <MiB> <bounces> "
 		"[hugetlbfs_file]\n\n");
+
 	fprintf(stderr, "Supported <test type>: anon, hugetlb, "
 		"hugetlb_shared, shmem\n\n");
+
+	fprintf(stderr, "'Test mods' can be joined to the test type string with a ':'. "
+		"Supported mods:\n");
+	fprintf(stderr, "\tdev - Use /dev/userfaultfd instead of userfaultfd(2)\n");
+	fprintf(stderr, "\nExample test mod usage:\n");
+	fprintf(stderr, "# Run anonymous memory test with /dev/userfaultfd:\n");
+	fprintf(stderr, "./userfaultfd anon:dev 100 99999\n\n");
+
 	fprintf(stderr, "Examples:\n\n");
 	fprintf(stderr, "%s", examples);
 	exit(1);
@@ -1610,8 +1619,6 @@  unsigned long default_huge_page_size(void)
 
 static void set_test_type(const char *type)
 {
-	uint64_t features = UFFD_API_FEATURES;
-
 	if (!strcmp(type, "anon")) {
 		test_type = TEST_ANON;
 		uffd_test_ops = &anon_uffd_test_ops;
@@ -1631,10 +1638,28 @@  static void set_test_type(const char *type)
 		test_type = TEST_SHMEM;
 		uffd_test_ops = &shmem_uffd_test_ops;
 		test_uffdio_minor = true;
-	} else {
-		err("Unknown test type: %s", type);
+	}
+}
+
+static void parse_test_type_arg(const char *raw_type)
+{
+	char *buf = strdup(raw_type);
+	uint64_t features = UFFD_API_FEATURES;
+
+	while (buf) {
+		const char *token = strsep(&buf, ":");
+
+		if (!test_type)
+			set_test_type(token);
+		else if (!strcmp(token, "dev"))
+			test_dev_userfaultfd = true;
+		else
+			err("unrecognized test mod '%s'", token);
 	}
 
+	if (!test_type)
+		err("failed to parse test type argument: '%s'", raw_type);
+
 	if (test_type == TEST_HUGETLB)
 		page_size = default_huge_page_size();
 	else
@@ -1681,7 +1706,7 @@  int main(int argc, char **argv)
 		err("failed to arm SIGALRM");
 	alarm(ALARM_INTERVAL_SECS);
 
-	set_test_type(argv[1]);
+	parse_test_type_arg(argv[1]);
 
 	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 	nr_pages_per_cpu = atol(argv[2]) * 1024*1024 / page_size /
@@ -1719,12 +1744,6 @@  int main(int argc, char **argv)
 	}
 	printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
 	       nr_pages, nr_pages_per_cpu);
-
-	test_dev_userfaultfd = false;
-	if (userfaultfd_stress())
-		return 1;
-
-	test_dev_userfaultfd = true;
 	return userfaultfd_stress();
 }