diff mbox series

[v2,2/3] userfaultfd/selftests: fix feature support detection

Message ID 20210930212309.4001967-3-axelrasmussen@google.com (mailing list archive)
State New
Headers show
Series Small userfaultfd selftest fixups | expand

Commit Message

Axel Rasmussen Sept. 30, 2021, 9:23 p.m. UTC
Before any tests are run, in set_test_type, we decide what feature(s) we
are going to be testing, based upon our command line arguments. However,
the supported features are not just a function of the memory type being
used, so this is broken.

For instance, consider writeprotect support. It is "normally" supported
for anonymous memory, but furthermore it requires that the kernel has
CONFIG_HAVE_ARCH_USERFAULTFD_WP. So, it is *not* supported at all on
aarch64, for example.

So, this commit fixes this by querying the kernel for the set of
features it supports in set_test_type, by opening a userfaultfd and
issuing a UFFDIO_API ioctl. Based upon the reported features, we toggle
what tests are enabled.

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

Comments

Axel Rasmussen Oct. 20, 2021, 6:28 p.m. UTC | #1
Just a friendly bump for review. :) Peter, any objections to this
version? I think it fairly closely matches your suggestions from v1.

On Thu, Sep 30, 2021 at 2:23 PM Axel Rasmussen <axelrasmussen@google.com> wrote:
>
> Before any tests are run, in set_test_type, we decide what feature(s) we
> are going to be testing, based upon our command line arguments. However,
> the supported features are not just a function of the memory type being
> used, so this is broken.
>
> For instance, consider writeprotect support. It is "normally" supported
> for anonymous memory, but furthermore it requires that the kernel has
> CONFIG_HAVE_ARCH_USERFAULTFD_WP. So, it is *not* supported at all on
> aarch64, for example.
>
> So, this commit fixes this by querying the kernel for the set of
> features it supports in set_test_type, by opening a userfaultfd and
> issuing a UFFDIO_API ioctl. Based upon the reported features, we toggle
> what tests are enabled.
>
> Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
> ---
>  tools/testing/selftests/vm/userfaultfd.c | 54 ++++++++++++++----------
>  1 file changed, 31 insertions(+), 23 deletions(-)
>
> diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
> index 2a71a91559a7..00d1b7555865 100644
> --- a/tools/testing/selftests/vm/userfaultfd.c
> +++ b/tools/testing/selftests/vm/userfaultfd.c
> @@ -346,6 +346,16 @@ static struct uffd_test_ops hugetlb_uffd_test_ops = {
>
>  static struct uffd_test_ops *uffd_test_ops;
>
> +static inline uint64_t uffd_minor_feature(void)
> +{
> +       if (test_type == TEST_HUGETLB && map_shared)
> +               return UFFD_FEATURE_MINOR_HUGETLBFS;
> +       else if (test_type == TEST_SHMEM)
> +               return UFFD_FEATURE_MINOR_SHMEM;
> +       else
> +               return 0;
> +}
> +
>  static void userfaultfd_open(uint64_t *features)
>  {
>         struct uffdio_api uffdio_api;
> @@ -406,7 +416,7 @@ static void uffd_test_ctx_clear(void)
>         munmap_area((void **)&area_dst_alias);
>  }
>
> -static void uffd_test_ctx_init_ext(uint64_t *features)
> +static void uffd_test_ctx_init(uint64_t features)
>  {
>         unsigned long nr, cpu;
>
> @@ -418,7 +428,7 @@ static void uffd_test_ctx_init_ext(uint64_t *features)
>         uffd_test_ops->release_pages(area_src);
>         uffd_test_ops->release_pages(area_dst);
>
> -       userfaultfd_open(features);
> +       userfaultfd_open(&features);
>
>         count_verify = malloc(nr_pages * sizeof(unsigned long long));
>         if (!count_verify)
> @@ -446,11 +456,6 @@ static void uffd_test_ctx_init_ext(uint64_t *features)
>                         err("pipe");
>  }
>
> -static inline void uffd_test_ctx_init(uint64_t features)
> -{
> -       uffd_test_ctx_init_ext(&features);
> -}
> -
>  static int my_bcmp(char *str1, char *str2, size_t n)
>  {
>         unsigned long i;
> @@ -1191,7 +1196,6 @@ static int userfaultfd_minor_test(void)
>         void *expected_page;
>         char c;
>         struct uffd_stats stats = { 0 };
> -       uint64_t req_features, features_out;
>
>         if (!test_uffdio_minor)
>                 return 0;
> @@ -1199,21 +1203,7 @@ static int userfaultfd_minor_test(void)
>         printf("testing minor faults: ");
>         fflush(stdout);
>
> -       if (test_type == TEST_HUGETLB)
> -               req_features = UFFD_FEATURE_MINOR_HUGETLBFS;
> -       else if (test_type == TEST_SHMEM)
> -               req_features = UFFD_FEATURE_MINOR_SHMEM;
> -       else
> -               return 1;
> -
> -       features_out = req_features;
> -       uffd_test_ctx_init_ext(&features_out);
> -       /* If kernel reports required features aren't supported, skip test. */
> -       if ((features_out & req_features) != req_features) {
> -               printf("skipping test due to lack of feature support\n");
> -               fflush(stdout);
> -               return 0;
> -       }
> +       uffd_test_ctx_init(uffd_minor_feature());
>
>         uffdio_register.range.start = (unsigned long)area_dst_alias;
>         uffdio_register.range.len = nr_pages * page_size;
> @@ -1574,6 +1564,8 @@ 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;
> @@ -1607,6 +1599,22 @@ static void set_test_type(const char *type)
>         if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2
>             > page_size)
>                 err("Impossible to run this test");
> +
> +       /*
> +        * Whether we can test certain features depends not just on test type,
> +        * but also on whether or not this particular kernel supports the
> +        * feature.
> +        */
> +
> +       userfaultfd_open(&features);
> +
> +       test_uffdio_wp = test_uffdio_wp &&
> +               (features & UFFD_FEATURE_PAGEFAULT_FLAG_WP);
> +       test_uffdio_minor = test_uffdio_minor &&
> +               (features & uffd_minor_feature());
> +
> +       close(uffd);
> +       uffd = -1;
>  }
>
>  static void sigalrm(int sig)
> --
> 2.33.0.800.g4c38ced690-goog
>
Peter Xu Oct. 21, 2021, 1:29 a.m. UTC | #2
On Wed, Oct 20, 2021 at 11:28:49AM -0700, Axel Rasmussen wrote:
> Just a friendly bump for review. :) Peter, any objections to this
> version? I think it fairly closely matches your suggestions from v1.

Isn't the whole patchset already queued by Andrew? :)

Anyway,

Reviewed-by: Peter Xu <peterx@redhat.com>

Thanks for the change!
Axel Rasmussen Oct. 27, 2021, 9:15 p.m. UTC | #3
On Wed, Oct 20, 2021 at 6:29 PM Peter Xu <peterx@redhat.com> wrote:
>
> On Wed, Oct 20, 2021 at 11:28:49AM -0700, Axel Rasmussen wrote:
> > Just a friendly bump for review. :) Peter, any objections to this
> > version? I think it fairly closely matches your suggestions from v1.
>
> Isn't the whole patchset already queued by Andrew? :)

Ah, true, but I was worried he might hold it there until it got a R-B?
The process is still a bit fuzzy to me. :) Thanks for taking a look in
any case!


>
> Anyway,
>
> Reviewed-by: Peter Xu <peterx@redhat.com>
>
> Thanks for the change!
>
> --
> Peter Xu
>
diff mbox series

Patch

diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
index 2a71a91559a7..00d1b7555865 100644
--- a/tools/testing/selftests/vm/userfaultfd.c
+++ b/tools/testing/selftests/vm/userfaultfd.c
@@ -346,6 +346,16 @@  static struct uffd_test_ops hugetlb_uffd_test_ops = {
 
 static struct uffd_test_ops *uffd_test_ops;
 
+static inline uint64_t uffd_minor_feature(void)
+{
+	if (test_type == TEST_HUGETLB && map_shared)
+		return UFFD_FEATURE_MINOR_HUGETLBFS;
+	else if (test_type == TEST_SHMEM)
+		return UFFD_FEATURE_MINOR_SHMEM;
+	else
+		return 0;
+}
+
 static void userfaultfd_open(uint64_t *features)
 {
 	struct uffdio_api uffdio_api;
@@ -406,7 +416,7 @@  static void uffd_test_ctx_clear(void)
 	munmap_area((void **)&area_dst_alias);
 }
 
-static void uffd_test_ctx_init_ext(uint64_t *features)
+static void uffd_test_ctx_init(uint64_t features)
 {
 	unsigned long nr, cpu;
 
@@ -418,7 +428,7 @@  static void uffd_test_ctx_init_ext(uint64_t *features)
 	uffd_test_ops->release_pages(area_src);
 	uffd_test_ops->release_pages(area_dst);
 
-	userfaultfd_open(features);
+	userfaultfd_open(&features);
 
 	count_verify = malloc(nr_pages * sizeof(unsigned long long));
 	if (!count_verify)
@@ -446,11 +456,6 @@  static void uffd_test_ctx_init_ext(uint64_t *features)
 			err("pipe");
 }
 
-static inline void uffd_test_ctx_init(uint64_t features)
-{
-	uffd_test_ctx_init_ext(&features);
-}
-
 static int my_bcmp(char *str1, char *str2, size_t n)
 {
 	unsigned long i;
@@ -1191,7 +1196,6 @@  static int userfaultfd_minor_test(void)
 	void *expected_page;
 	char c;
 	struct uffd_stats stats = { 0 };
-	uint64_t req_features, features_out;
 
 	if (!test_uffdio_minor)
 		return 0;
@@ -1199,21 +1203,7 @@  static int userfaultfd_minor_test(void)
 	printf("testing minor faults: ");
 	fflush(stdout);
 
-	if (test_type == TEST_HUGETLB)
-		req_features = UFFD_FEATURE_MINOR_HUGETLBFS;
-	else if (test_type == TEST_SHMEM)
-		req_features = UFFD_FEATURE_MINOR_SHMEM;
-	else
-		return 1;
-
-	features_out = req_features;
-	uffd_test_ctx_init_ext(&features_out);
-	/* If kernel reports required features aren't supported, skip test. */
-	if ((features_out & req_features) != req_features) {
-		printf("skipping test due to lack of feature support\n");
-		fflush(stdout);
-		return 0;
-	}
+	uffd_test_ctx_init(uffd_minor_feature());
 
 	uffdio_register.range.start = (unsigned long)area_dst_alias;
 	uffdio_register.range.len = nr_pages * page_size;
@@ -1574,6 +1564,8 @@  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;
@@ -1607,6 +1599,22 @@  static void set_test_type(const char *type)
 	if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2
 	    > page_size)
 		err("Impossible to run this test");
+
+	/*
+	 * Whether we can test certain features depends not just on test type,
+	 * but also on whether or not this particular kernel supports the
+	 * feature.
+	 */
+
+	userfaultfd_open(&features);
+
+	test_uffdio_wp = test_uffdio_wp &&
+		(features & UFFD_FEATURE_PAGEFAULT_FLAG_WP);
+	test_uffdio_minor = test_uffdio_minor &&
+		(features & uffd_minor_feature());
+
+	close(uffd);
+	uffd = -1;
 }
 
 static void sigalrm(int sig)