$RodHat_
Syscall reference · Memory

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

NameWhat it does
O_CLOEXECSet close-on-exec on the new userfaultfd.
O_NONBLOCKNon-blocking reads; use poll(2)/epoll(7) to wait for events.
UFFD_USER_MODE_ONLYLinux 5.11Only handle faults originating in user space; kernel-originated faults get SIGBUS.
UFFDIO_REGISTER_MODE_MISSINGLinux 4.10Notify on access to a missing page; resolve with UFFDIO_COPY or UFFDIO_ZEROPAGE.
UFFDIO_REGISTER_MODE_WPLinux 5.7Notify on writes to write-protected pages; resolve with UFFDIO_WRITEPROTECT.
UFFDIO_REGISTER_MODE_MINORLinux 5.13Notify on minor faults (page in page cache, no PTE); resolve with UFFDIO_CONTINUE.
UFFDIO_REGISTER_MODE_RWPLinux 7.2Notify on any read or write to a present page; can't be combined with MODE_WP.
UFFD_EVENT_FORK / REMAP / REMOVE / UNMAPLinux 4.11Non-page-fault events about VM layout changes, enabled via UFFDIO_API features.

Errors you will actually hit

errnoMeaning
EPERMSince Linux 5.2: no CAP_SYS_PTRACE in the initial user ns and vm.unprivileged_userfaultfd is 0.
EINVALAn unsupported value was specified in flags.
EMFILEPer-process open file descriptor limit reached.
ENOMEMInsufficient 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, &reg) < 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

  1. userfaultfd(2), man7.org

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.