Message ID | 20220422212945.2227722-4-axelrasmussen@google.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | userfaultfd: add /dev/userfaultfd for fine grained access control | expand |
On 4/22/22 3:29 PM, Axel Rasmussen wrote: > We clearly want to ensure both userfaultfd(2) and /dev/userfaultfd keep > working into the future, so just run the test twice, using each > interface. > > Signed-off-by: Axel Rasmussen <axelrasmussen@google.com> > --- > tools/testing/selftests/vm/userfaultfd.c | 31 ++++++++++++++++++++++-- > 1 file changed, 29 insertions(+), 2 deletions(-) > > diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c > index 92a4516f8f0d..12ae742a9981 100644 > --- a/tools/testing/selftests/vm/userfaultfd.c > +++ b/tools/testing/selftests/vm/userfaultfd.c > @@ -77,6 +77,9 @@ static int bounces; > #define TEST_SHMEM 3 > static int test_type; > > +/* test using /dev/userfaultfd, instead of userfaultfd(2) */ > +static bool test_dev_userfaultfd; > + > /* exercise the test_uffdio_*_eexist every ALARM_INTERVAL_SECS */ > #define ALARM_INTERVAL_SECS 10 > static volatile bool test_uffdio_copy_eexist = true; > @@ -383,13 +386,31 @@ static void assert_expected_ioctls_present(uint64_t mode, uint64_t ioctls) > } > } > > +static void __userfaultfd_open_dev(void) > +{ > + int fd; > + > + uffd = -1; > + fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC); > + if (fd < 0) > + return; > + > + uffd = ioctl(fd, USERFAULTFD_IOC_NEW, > + O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); > + close(fd); > +} > + > static void userfaultfd_open(uint64_t *features) > { > struct uffdio_api uffdio_api; > > - uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); > + if (test_dev_userfaultfd) > + __userfaultfd_open_dev(); > + else > + uffd = syscall(__NR_userfaultfd, > + O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); > if (uffd < 0) > - err("userfaultfd syscall not available in this kernel"); > + err("creating userfaultfd failed"); This isn't an error as in test failure. This will be a skip because of unmet dependencies. Also if this test requires root access, please check for that and make that a skip as well. > uffd_flags = fcntl(uffd, F_GETFD, NULL); > > uffdio_api.api = UFFD_API; > @@ -1698,6 +1719,12 @@ 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(); > } > > thanks, -- Shuah
On Tue, Apr 26, 2022 at 9:16 AM Shuah Khan <skhan@linuxfoundation.org> wrote: > > On 4/22/22 3:29 PM, Axel Rasmussen wrote: > > We clearly want to ensure both userfaultfd(2) and /dev/userfaultfd keep > > working into the future, so just run the test twice, using each > > interface. > > > > Signed-off-by: Axel Rasmussen <axelrasmussen@google.com> > > --- > > tools/testing/selftests/vm/userfaultfd.c | 31 ++++++++++++++++++++++-- > > 1 file changed, 29 insertions(+), 2 deletions(-) > > > > diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c > > index 92a4516f8f0d..12ae742a9981 100644 > > --- a/tools/testing/selftests/vm/userfaultfd.c > > +++ b/tools/testing/selftests/vm/userfaultfd.c > > @@ -77,6 +77,9 @@ static int bounces; > > #define TEST_SHMEM 3 > > static int test_type; > > > > +/* test using /dev/userfaultfd, instead of userfaultfd(2) */ > > +static bool test_dev_userfaultfd; > > + > > /* exercise the test_uffdio_*_eexist every ALARM_INTERVAL_SECS */ > > #define ALARM_INTERVAL_SECS 10 > > static volatile bool test_uffdio_copy_eexist = true; > > @@ -383,13 +386,31 @@ static void assert_expected_ioctls_present(uint64_t mode, uint64_t ioctls) > > } > > } > > > > +static void __userfaultfd_open_dev(void) > > +{ > > + int fd; > > + > > + uffd = -1; > > + fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC); > > + if (fd < 0) > > + return; > > + > > + uffd = ioctl(fd, USERFAULTFD_IOC_NEW, > > + O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); > > + close(fd); > > +} > > + > > static void userfaultfd_open(uint64_t *features) > > { > > struct uffdio_api uffdio_api; > > > > - uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); > > + if (test_dev_userfaultfd) > > + __userfaultfd_open_dev(); > > + else > > + uffd = syscall(__NR_userfaultfd, > > + O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); > > if (uffd < 0) > > - err("userfaultfd syscall not available in this kernel"); > > + err("creating userfaultfd failed"); > > This isn't an error as in test failure. This will be a skip because of > unmet dependencies. Also if this test requires root access, please check > for that and make that a skip as well. Testing with the userfaultfd syscall doesn't require any special permissions (root or otherwise). But testing with /dev/userfaultfd will require access to that device node, which is root:root by default, but the system administrator may have changed this. In general I think this will only fail due to a) lack of kernel support or b) lack of permissions though, so always exiting with KSFT_SKIP here seems reasonable. I'll make that change in v3. > > > uffd_flags = fcntl(uffd, F_GETFD, NULL); > > > > uffdio_api.api = UFFD_API; > > @@ -1698,6 +1719,12 @@ 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(); > > } > > > > > > thanks, > -- Shuah
diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index 92a4516f8f0d..12ae742a9981 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -77,6 +77,9 @@ static int bounces; #define TEST_SHMEM 3 static int test_type; +/* test using /dev/userfaultfd, instead of userfaultfd(2) */ +static bool test_dev_userfaultfd; + /* exercise the test_uffdio_*_eexist every ALARM_INTERVAL_SECS */ #define ALARM_INTERVAL_SECS 10 static volatile bool test_uffdio_copy_eexist = true; @@ -383,13 +386,31 @@ static void assert_expected_ioctls_present(uint64_t mode, uint64_t ioctls) } } +static void __userfaultfd_open_dev(void) +{ + int fd; + + uffd = -1; + fd = open("/dev/userfaultfd", O_RDWR | O_CLOEXEC); + if (fd < 0) + return; + + uffd = ioctl(fd, USERFAULTFD_IOC_NEW, + O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); + close(fd); +} + static void userfaultfd_open(uint64_t *features) { struct uffdio_api uffdio_api; - uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); + if (test_dev_userfaultfd) + __userfaultfd_open_dev(); + else + uffd = syscall(__NR_userfaultfd, + O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); if (uffd < 0) - err("userfaultfd syscall not available in this kernel"); + err("creating userfaultfd failed"); uffd_flags = fcntl(uffd, F_GETFD, NULL); uffdio_api.api = UFFD_API; @@ -1698,6 +1719,12 @@ 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(); }
We clearly want to ensure both userfaultfd(2) and /dev/userfaultfd keep working into the future, so just run the test twice, using each interface. Signed-off-by: Axel Rasmussen <axelrasmussen@google.com> --- tools/testing/selftests/vm/userfaultfd.c | 31 ++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-)