userfaultfd(2)
Create an fd that lets userspace resolve page faults on registered memory ranges.
- Since
- Linux 4.3check your kernel →
- glibc
- none (use syscall(2))
- System
- Linux
- Man page
- userfaultfd(2)
Synopsis
#include <fcntl.h>
#include <sys/syscall.h>
#include <linux/userfaultfd.h>
#include <unistd.h>
int syscall(SYS_userfaultfd, int flags);Rod's take
Normally a touch on a missing page gets you SIGSEGV and a funeral. userfaultfd says hold on, I'll supply that page myself: the faulting thread stalls, a handler reads the event off the fd, fills the page with UFFDIO_COPY, and the thread carries on none the wiser. That's the trick under post-copy migration and lazy restore. The rule that bites everyone once: the handler must never fault on the region it's serving, or you've built a very elegant deadlock. Unprivileged use hinges on vm.unprivileged_userfaultfd, so check before you promise anybody anything.
Flags and arguments that matter
| Name | What it does |
|---|---|
| O_CLOEXEC | Set close-on-exec on the new userfaultfd. |
| O_NONBLOCK | Non-blocking reads; use poll(2)/epoll(7) to wait for events. |
| UFFD_USER_MODE_ONLYLinux 5.11 | Only handle faults originating in user space; kernel-originated faults get SIGBUS. |
| UFFDIO_REGISTER_MODE_MISSINGLinux 4.10 | Notify on access to a missing page; resolve with UFFDIO_COPY or UFFDIO_ZEROPAGE. |
| UFFDIO_REGISTER_MODE_WPLinux 5.7 | Notify on writes to write-protected pages; resolve with UFFDIO_WRITEPROTECT. |
| UFFDIO_REGISTER_MODE_MINORLinux 5.13 | Notify on minor faults (page in page cache, no PTE); resolve with UFFDIO_CONTINUE. |
| UFFDIO_REGISTER_MODE_RWPLinux 7.2 | Notify on any read or write to a present page; can't be combined with MODE_WP. |
| UFFD_EVENT_FORK / REMAP / REMOVE / UNMAPLinux 4.11 | Non-page-fault events about VM layout changes, enabled via UFFDIO_API features. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EPERM | Since Linux 5.2: no CAP_SYS_PTRACE in the initial user ns and vm.unprivileged_userfaultfd is 0. |
| EINVAL | An unsupported value was specified in flags. |
| EMFILE | Per-process open file descriptor limit reached. |
| ENOMEM | Insufficient kernel memory. |
Example
int uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd < 0)
err(1, "userfaultfd"); /* EPERM: vm.unprivileged_userfaultfd */
struct uffdio_api api = { .api = UFFD_API, .features = 0 };
if (ioctl(uffd, UFFDIO_API, &api) < 0)
err(1, "UFFDIO_API");
struct uffdio_register reg = {
.range = { .start = (uintptr_t)region, .len = len },
.mode = UFFDIO_REGISTER_MODE_MISSING,
};
if (ioctl(uffd, UFFDIO_REGISTER, ®) < 0)
err(1, "UFFDIO_REGISTER");
/* handler thread: poll(), read struct uffd_msg, UFFDIO_COPY */Trimmed from the full walkthrough in userfaultfd: handle your own page faults from userspace.
BSD equivalent
none
The long version, from the console
Sources
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
