Skip to content

Conversation

@ricardobranco777
Copy link

@ricardobranco777 ricardobranco777 commented Dec 7, 2025

Add more tests for userfaultfd:

  • UFFDIO_MOVE
  • UFFDIO_WRITEPROTECT
  • UFFDIO_ZEROPAGE
  • UFFD_USER_MODE_ONLY
  • Use /dev/userfaultfd instead of system call

@ricardobranco777 ricardobranco777 force-pushed the userfaultfd branch 8 times, most recently from 45b04e6 to bffe686 Compare December 8, 2025 11:38
Copy link
Member

@metan-ucw metan-ucw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but there is too much duplicated code (should be mostly put into a common header) and some minor errors as well.

SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);

SAFE_PTHREAD_CREATE(&thr, NULL,
(void * (*)(void *)) handle_thread, NULL);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be just (void*) cast, but it would be better if the handle_thread function was defined as void * and returned NULL at the end.

tst_brk(TBROK | TTERRNO,
"Could not create userfault file descriptor");
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sys_userfaultfd() should be in the test setup() so that things work properly when test is executed with -1 1000 parameter.

Also this pattern is repeated in all tests, so this piece of code should be put into a header as a static inline function and called from all tests that needs it.

static struct tst_test test = {
.test_all = run,
.min_kver = "5.11",
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nearly the same as the userfaultfd01, it just adds the UFFD_USER_MODE_ONLY flag. It would be far better if we added .tcnt = 2 to the usefaultfd02.c and add the flag to the uffdio_register.mode only when n == 1 in order to avoid copy & paste of basically the same test.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .min_kver is different though.


/*\
* Force a pagefault event and handle it using :man2:`userfaultfd`
* from a different thread using /dev/userfaultfd instead of syscall.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should mention the details here, in this case we do UFFDIO_COPY and use file descriptor created by USERFAULTFD_IOC_NEW

SAFE_PTHREAD_CREATE(&thr, NULL,
(void * (*)(void *)) handle_thread, NULL);

(void)page[0xf];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think that we need this here, we are checking the page in the loop below, which will trigger read access anyways.

pollfd.events = POLLIN;
nready = poll(&pollfd, 1, -1);
if (nready == -1)
tst_brk(TBROK | TERRNO, "Error on poll");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the poll() here? We are waiting indefinitely anyways so as long as uffd is not O_NONBLOCK (which should be default) we can just remove this and call the SAFE_READ() which will wait for the data.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the poll() here? We are waiting indefinitely anyways so as long as uffd is not O_NONBLOCK (which should be default) we can just remove this and call the SAFE_READ() which will wait for the data.

Technically no but uffd's are universally opened in non-blocking mode to use with poll as it seems it's the only way to catch some errors:

https://docs.kernel.org/admin-guide/mm/userfaultfd.html

Be sure to test for all errors including (pollfd[0].revents & POLLERR). This can happen, e.g. when ranges supplied were incorrect.

uffdio_zeropage.range.len = page_size;
uffdio_zeropage.mode = 0;

SAFE_IOCTL(uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that we need a test where we will attempt to map a ZEROPAGE for a write access, I suppose that we will get error from this ioctl()

(void)page[0xf];

for (int i = 0; i < page_size; i++) {
if (page[i] != '\0') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just use 0 instead of '\0'

SAFE_READ(1, uffd, &msg, sizeof(msg));

if (msg.event != UFFD_EVENT_PAGEFAULT)
tst_brk(TBROK | TERRNO, "Received unexpected UFFD_EVENT");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's TFAIL


if (!(msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WP) ||
!(msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE)) {
tst_brk(TBROK,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here as well TFAIL

Signed-off-by: Ricardo Branco <rbranco@suse.de>
Signed-off-by: Ricardo Branco <rbranco@suse.de>
Signed-off-by: Ricardo Branco <rbranco@suse.de>
Signed-off-by: Ricardo Branco <rbranco@suse.de>
Signed-off-by: Ricardo Branco <rbranco@suse.de>
Signed-off-by: Ricardo Branco <rbranco@suse.de>
Signed-off-by: Ricardo Branco <rbranco@suse.de>
@ricardobranco777
Copy link
Author

Looks good, but there is too much duplicated code (should be mostly put into a common header) and some minor errors as well.

Thanks for reviewing. I addressed most of your suggestions. Left some questions regarding further refactoring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants