A memory access normally enters the kernel page-fault path and completes without an application choosing the page contents at that instant. Linux userfaultfd changes that boundary for registered virtual address ranges: selected faults become events on a file descriptor, and a user-space manager can supply or activate the page before the faulting thread continues.

The mechanism does not replace the process page tables with a user-space data structure. The kernel still owns page-table state and performs the final mapping operation. User space gains control over specific fault classes and the timing of their resolution.

Registration defines which faults leave the normal path

A userfaultfd object must first complete the UFFDIO_API handshake. That exchange establishes the API version and negotiates optional kernel features. Memory ranges are then attached with UFFDIO_REGISTER, together with one or more supported registration modes.

UFFDIO_REGISTER_MODE_MISSING intercepts accesses for which the registered range has no populated page. The accessing thread is blocked while the event is pending. A manager can resolve the fault with UFFDIO_COPY, which installs supplied contents, or UFFDIO_ZEROPAGE, which provides a zero-filled page where that operation is supported.

Registration is range-specific. An address outside the registered interval follows the ordinary memory-management path, and a registered interval only produces events for fault classes enabled for that range.

Fault delivery separates the blocked thread from the pager

Page-fault events are read as uffd_msg records from the descriptor. A manager commonly runs in another thread or process so it can continue executing while the thread that touched the faulting address is stopped.

The event includes the faulting address and flags that identify relevant properties such as a write, write-protection fault, or minor fault. Optional feature negotiation can also expose the thread ID that generated the event.

This split creates a scheduling dependency that does not exist in ordinary demand paging. A fault can remain unresolved while the manager fetches data, reconstructs state, or coordinates with another component. The faulting thread cannot make progress through that access until the required resolution operation completes.

Resolution operations publish complete page state

UFFDIO_COPY copies page contents from a user-space source into the faulting range. UFFDIO_ZEROPAGE establishes zero-filled contents. For minor faults, UFFDIO_CONTINUE activates an existing backing page after the manager decides it is ready.

These operations provide an atomic visibility boundary for the affected page. Other threads do not observe a partially copied page through the faulting mapping while UFFDIO_COPY is in progress. Threads that encounter the unresolved state continue to fault until the kernel completes the resolution.

By default, a successful resolution also wakes blocked faulting threads for the affected range. The DONTWAKE variants separate population from wakeup, allowing a manager to resolve several pages and issue wakeups separately.

Minor faults control activation rather than page creation

UFFDIO_REGISTER_MODE_MINOR targets a different state from missing-page mode. A minor fault can occur when the backing page already exists, but the page-table entry needed by the faulting mapping has not been installed.

For supported shmem and hugetlbfs mappings, the manager can inspect or modify the backing page through another mapping before issuing UFFDIO_CONTINUE. The final ioctl tells the kernel that the existing page may now become visible through the faulting mapping.

This distinction matters for migration and memory-management systems. Missing mode controls what page is supplied. Minor mode can interpose on the point at which an already present backing page becomes accessible through a particular mapping.

Write-protect mode turns writes into synchronous events

UFFDIO_REGISTER_MODE_WP adds another fault class. After a range is registered and protected with UFFDIO_WRITEPROTECT, a write to a protected page can generate a userfaultfd event. The event carries the write-protection flag, and the writing thread remains blocked until the manager removes the protection or otherwise resolves the state.

This mode can support precise dirty-page tracking because the first protected write can be observed at the memory-access boundary. It is distinct from missing mode: registering only write-protect mode does not by itself request notifications for ordinary missing pages.

Support differs by memory type and kernel feature set, so feature negotiation is part of the interface contract rather than an optional compatibility check.

Access policy limits which faults can be delegated

Creation through the userfaultfd() system call is subject to kernel policy. UFFD_USER_MODE_ONLY creates an object restricted to faults originating from user mode. Handling kernel-originated faults through that interface requires the permissions or system configuration documented by the kernel.

Linux also provides /dev/userfaultfd on systems that expose it. Access to that device is governed through filesystem permissions, giving administrators a separate control point for creating userfaultfd objects with broader fault-handling capability.

These controls are security boundaries. Delegating page-fault handling can affect execution of threads that touch registered memory, so availability cannot be inferred solely from the presence of the syscall number.

Closing the descriptor removes the delegated boundary

The registration lifetime is tied to the userfaultfd object. When the last file descriptor referring to it is closed, registered ranges are unregistered and unread events are discarded.

A pager therefore needs failure handling for the manager itself, not only for individual ioctl calls. A design that depends on remote page supply, live migration, checkpoint restoration, or application-level paging must define what happens when the component responsible for resolving faults exits or loses access to its data source.

userfaultfd places a controlled interception point inside Linux virtual-memory fault handling. The kernel retains authority over mappings, while user space can decide the contents or activation of selected pages and can delay the threads that require them until that state is ready.