move_pages(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… move_pages(9) πŸ’…

okay bestie, this is the move_pages(9) page from the Kernel API Manual, and it's literally about moving arbitrary anonymous pages of an existing vma. no cap, it's a whole userfaultfd mood. πŸ¦‹


✨ NAME ✨

move_pages β€” move arbitrary anonymous pages of an existing vma πŸŽ€


🌸 SYNOPSIS 🌸

ssize_t move_pages (struct userfaultfd_ctx *ctx , unsigned long
       dst_start , unsigned long src_start , unsigned long len , __u64 mode );

πŸŽ€ ARGUMENTS πŸŽ€

  • ctx β€” pointer to the userfaultfd context πŸ’–
  • dst_start β€” start of the destination virtual memory range ✨
  • src_start β€” start of the source virtual memory range 🌸
  • len β€” length of the virtual memory range πŸŽ€
  • mode β€” flags from uffdio_move.mode πŸ¦‹

πŸ¦‹ DESCRIPTION πŸ¦‹

It will either use the mmap_lock in read mode or per-vma locks. πŸ’…

move_pages remaps arbitrary anonymous pages atomically in zero copy. It only works on non shared anonymous pages because those can be relocated without generating non linear anon_vmas in the rmap code. πŸ‘‘

It provides a zero copy mechanism to handle userspace page faults. The source vma pages should have mapcount == 1, which can be enforced by using madvise(MADV_DONTFORK) on src vma. 🫢

The thread receiving the page during the userland page fault will receive the faulting page in the source vma through the network, storage or any other I/O device (MADV_DONTFORK in the source vma avoids move_pages to fail with -EBUSY if the process forks before move_pages is called), then it will call move_pages to map the page in the faulting address in the destination vma. 😭✨

This userfaultfd command works purely via pagetables, so it's the most efficient way to move physical non shared anonymous pages across different virtual addresses. Unlike mremap/mmap/munmap it does not create any new vmas. The mapping in the destination address is atomic. πŸ”₯

It only works if the vma protection bits are identical from the source and destination vma. 🌈

It can remap non shared anonymous pages within the same vma too. 🧚

If the source virtual memory range has any unmapped holes, or if the destination virtual memory range is not a whole unmapped hole, move_pages will fail respectively with -ENOENT or -EEXIST. This provides a very strict behavior to avoid any chance of memory corruption going unnoticed if there are userland race conditions. Only one thread should resolve the userland page fault at any given time for any given faulting address. This means that if two threads try to both call move_pages on the same destination address at the same time, the second thread will get an explicit error from this command. πŸ’€

The command retval will return "len" is successful. The command however can be interrupted by fatal signals or errors. If interrupted it will return the number of bytes successfully remapped before the interruption if any, or the negative error if none. It will never return zero. Either it will return an error or an amount of bytes successfully moved. If the retval reports a "short" remap, the move_pages command should be repeated by userland with src+retval, dst+reval, len-retval if it wants to know about the error that interrupted it. πŸ™ˆ

The UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES flag can be specified to prevent -ENOENT errors to materialize if there are holes in the source virtual range that is being remapped. The holes will be accounted as successfully remapped in the retval of the command. This is mostly useful to remap hugepage naturally aligned virtual regions without knowing if there are transparent hugepage in the regions or not, but preventing the risk of having to split the hugepmd during the remap. 🌟


🌈 SEE ALSO 🌈

Kernel file ./mm/userfaultfd.c userfaultfd_ctx_get(9), userfaultfd_ctx_put(9) 🫢


and that's the tea, bestie πŸ“ β€” this page comes from the ./mm source, October 2026, move_pages(9). πŸ’–

πŸ“¦ where this page comes from