move_pages(2)
๐ซ move_pages(2) โ the system call manual, but make it cute โจ
okay bestie, welcome to the System Calls Manual ๐ this one is called move_pages and it's lowkey one of the most fun little NUMA calls out there โ it's literally the "pick up this page and put it over THERE" spell ๐ฆ
๐ธ NAME ๐ธ
move_pages โ move individual pages of a process to another node ๐
๐ LIBRARY ๐
NUMA (Non-Uniform Memory Access) policy library (libnuma, -lnuma) ๐
โจ SYNOPSIS โจ
#include <numaif.h>
long move_pages(int pid, unsigned long count, void *pages[count],
const int nodes[count], int status[count],
int flags);
๐ DESCRIPTION ๐
So move_pages() takes the pages you point at for the process pid and moves them to the memory nodes you list in nodes. ๐โจ The results of the whole move situation show up in status. And flags tells the kernel what kind of constraints apply to the pages getting moved. no cap.
pid is the ID of the process whose pages are gonna get moved. And here's the cute part โ if pid is 0, then move_pages() just moves pages of the calling process (that's you, babe ๐).
But if you wanna move pages in another process, you need the following privileges:
- Up to and including Linux 4.12: the caller must be privileged (
CAP_SYS_NICE) or the real or effective user ID of the calling process must match the real or saved-set user ID of the target process. - The older rules allowed the caller to discover various virtual address choices made by the kernel that could lead to the defeat of address-space-layout randomization for a process owned by the same UID as the caller, the rules were changed starting with Linux 4.13. Since Linux 4.13, permission is governed by a
ptraceaccess modePTRACE_MODE_READ_REALCREDScheck with respect to the target process; seeptrace(2).
โ ๏ธ bestie that second bullet is the glow-up lore โ old rules were leaky, Linux 4.13 said "not today" and switched to a PTRACE_MODE_READ_REALCREDS check. remember it. ๐
count is how many pages you're moving. It also defines the size of the three arrays: pages, nodes, and status. โจ
pages is an array of pointers to the pages that should be moved. These are pointers that should be aligned to page boundaries ๐. Addresses are specified as seen by the process specified by pid.
nodes is an array of integers that specify the desired location for each page. Each element is a node number. And guess what โ nodes can also be NULL!! ๐ In that case move_pages() doesn't move anything, it just returns the node where each page currently resides, in the status array. This is genuinely so useful because sometimes you just gotta know which pages need moving before you move them. vibe check first, migrATE later ๐
status is an array of integers that return the status of each page. The array only contains valid values if move_pages() did NOT return an error. pro tip from the manpage: preinitializing the array to a value that can't represent a real numa node or a valid error of the status array could help you spot which pages actually got migrated ๐โจ
flags specify what types of pages to move. MPOL_MF_MOVE means only pages that are in exclusive use by the process are to be moved. MPOL_MF_MOVE_ALL means pages shared between multiple processes can also be moved ๐ซถ โ but the process must be privileged (CAP_SYS_NICE) to use MPOL_MF_MOVE_ALL. iconic but gated.
๐ฆ Page states in the status array ๐ฆ
These are the values that can be returned in each element of the status array:
0..MAX_NUMNODESโ Identifies the node on which the page resides. ๐-EACCESโ The page is mapped by multiple processes and can be moved only ifMPOL_MF_MOVE_ALLis specified.-EBUSYโ The page is currently busy and cannot be moved. Try again later. This occurs if a page is undergoing I/O or another kernel subsystem is holding a reference to the page. ๐ญ-EFAULTโ This is a zero page or the memory area is not mapped by the process.-EIOโ Unable to write back a page. The page has to be written back in order to move it since the page is dirty and the filesystem does not provide a migration function that would allow the move of dirty pages. ๐-EINVALโ A dirty page cannot be moved. The filesystem does not provide a migration function and has no ability to write back pages.-ENOENTโ The page is not present.-ENOMEMโ Unable to allocate memory on target node.
๐ RETURN VALUE ๐
On success move_pages() returns zero ๐. On error, it returns -1, and sets errno to indicate the error. And if a positive value is returned, it's the number of nonmigrated pages. So likeโฆ "how many of these lil guys refused to move", basically. ๐
๐ฅ ERRORS ๐ฅ
- Positive value โ The number of nonmigrated pages if they were the result of nonfatal reasons (since Linux 4.17).
E2BIGโ Too many pages to move. Since Linux 2.6.29, the kernel no longer generates this error. (rip, gone but not forgotten ๐ชฆ)EACCESโ One of the target nodes is not allowed by the current cpuset.EFAULTโ Parameter array could not be accessed.EINVALโ Flags other thanMPOL_MF_MOVEandMPOL_MF_MOVE_ALLwas specified or an attempt was made to migrate pages of a kernel thread. โENODEVโ One of the target nodes is not online. ๐ซฅEPERMโ The caller specifiedMPOL_MF_MOVE_ALLwithout sufficient privileges (CAP_SYS_NICE). Or, the caller attempted to move pages of a process belonging to another user but did not have privilege to do so (CAP_SYS_NICE).ESRCHโ Process does not exist. ๐ญ
๐ STANDARDS ๐
Linux. ๐ง periodt.
โญ HISTORY โญ
Linux 2.6.18. baby's first appearance ๐ซ
๐ธ NOTES ๐ธ
For information on library support, see numa(7).
Use get_mempolicy(2) with the MPOL_F_MEMS_ALLOWED flag to obtain the set of nodes that are allowed by the current cpuset. Note that this information is subject to change at any time by manual or automatic reconfiguration of the cpuset. โณ (yes it can change under you. ngl stay on your toes.)
Use of this function may result in pages whose location (node) violates the memory policy established for the specified addresses (see mbind(2)) and/or the specified process (see set_mempolicy(2)). That is, memory policy does not constrain the destination nodes used by move_pages(). ๐จ so like โ your memory policy does NOT hold this function back. it does what it wants. main character energy fr.
The <numaif.h> header is not included with glibc, but requires installing libnuma-devel or a similar package. ๐ฆ
๐ซถ SEE ALSO ๐ซถ
get_mempolicy(2), mbind(2), set_mempolicy(2), numa(3), numa_maps(5), cpuset(7), numa(7), migratepages(8), numastat(8)
okay that's the whole thing and you ATE it ๐ this page came from the Linux man-pages 6.20 collection, dated 2026-02-08 โ go forth and migrate responsibly, bestie ๐งโจ๐
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft
- Copyright 2006, Silicon Graphics, Inc
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms