migrate_pages(2)
๐ migrate_pages(2) โ the migrate_pages system call, bestie edition ๐
okay so we're in section 2 of the manual (system calls, the spicy stuff) and today's main character is migrate_pages. she moves memory around. she's iconic. let's get into it ๐ฆ
โจ NAME โจ
migrate_pages โ move all pages in a process to another set of nodes
๐ LIBRARY ๐
NUMA (Non-Uniform Memory Access) policy library โ that's libnuma, and you link it with -lnuma. ๐
๐ธ SYNOPSIS ๐ธ
#include <numaif.h>
long migrate_pages(int pid, unsigned long maxnode,
const unsigned long *old_nodes,
const unsigned long *new_nodes);
๐ซ DESCRIPTION ๐ซ
so basically migrate_pages() is like... a glow-up for your memory. it attempts to move all pages of the process pid that live in the memory nodes listed in old_nodes over to the memory nodes listed in new_nodes. that's it, that's the whole vibe. โจ
pages that aren't in any node of old_nodes? not migrated, not invited, not on the guest list. sorry babe. ๐
and here's the cute part โ as far as possible, the kernel maintains the relative topology relationship inside old_nodes during the migration to new_nodes. like, she keeps the friend group together when she moves them. queen behavior honestly ๐
now, old_nodes and new_nodes are pointers to bit masks of node numbers, with up to maxnode bits in each mask. these masks are stored as arrays of unsigned long integers โ and in the last long integer, the bits beyond those specified by maxnode are ignored. so don't stress about the stragglers at the end, they don't count. ๐
and maxnode is the maximum node number in the bit mask plus one. yep, plus one โ the off-by-one is real but it's honestly giving same energy as mbind(2), different from select(2) tho. don't mix them up, iykyk.
then there's pid: the ID of the process whose pages are to be moved. if you wanna move pages in another process, you've gotta be privileged โ that's CAP_SYS_NICE โ or your real or effective user ID has to match the real or saved-set user ID of the target process. no sneaking into other people's memory, bestie. ๐ซ
oh and if pid is 0? then migrate_pages() moves pages of the calling process. self-care!! ๐
โ ๏ธ and listen โ pages shared with another process will be moved only if the initiating process has the CAP_SYS_NICE privilege. shared custody requires paperwork fr fr.
๐ฅ RETURN VALUE ๐ฅ
on success, migrate_pages() returns the number of pages that could not be moved โ so yeah, heads up, a return of zero means that all pages were successfully moved. zero is the slay. anything else is leftovers. ๐
on error it returns -1, and sets errno to indicate the error. classic.
๐ ERRORS ๐
EFAULTโ part or all of the memory range specified byold_nodes/new_nodesandmaxnodepoints outside your accessible address space. she went somewhere she wasn't allowed ๐ญEINVALโ the value specified bymaxnodeexceeds a kernel-imposed limit. or,old_nodesornew_nodesspecifies one or more node IDs that are greater than the maximum supported node ID. or, none of the node IDs specified bynew_nodesare on-line and allowed by the process's current cpuset context, or none of the specified nodes contain memory. so many ways to be invalid, pls pick one ๐EPERMโ insufficient privilege (CAP_SYS_NICE) to move pages of the process specified bypid, or insufficient privilege (CAP_SYS_NICE) to access the specified target nodes. no badge, no entry ๐ESRCHโ no process matchingpidcould be found. she's not here. she ghosted. ๐ป
โญ STANDARDS โญ
Linux. (just linux, bestie, nothing else claimed her) ๐
๐ฆ HISTORY ๐ฆ
Linux 2.6.16. ancient. vintage. still serving looks. โจ
๐ NOTES ๐
for info on the library support, go peek at numa(7). ๐
use get_mempolicy(2) with the MPOL_F_MEMS_ALLOWED flag to obtain the set of nodes that are allowed by the calling process's cpuset. but โ note that this information is subject to change at any time by manual or automatic reconfiguration of the cpuset. so don't get too attached, it's giving situationship. ๐ญ
โ ๏ธ also real talk: use ofmigrate_pages()may result in pages whose location (node) violates the memory policy established for the specified addresses (seembind(2)) and/or the specified process (seeset_mempolicy(2)). that is, memory policy does not constrain the destination nodes used bymigrate_pages(). she does what she wants. respectful queen but also chaotic. ๐
and the <numaif.h> header is not included with glibc โ you've gotta install libnuma-devel or a similar package. go install it, i'll wait ๐ซถ
๐ SEE ALSO ๐
get_mempolicy(2)mbind(2)set_mempolicy(2)numa(3)numa_maps(5)cpuset(7)numa(7)migratepages(8)numastat(8)Documentation/vm/page_migration.rstin the Linux kernel source tree
okay that's the whole page babes, and real quick the sign-off: this gem is from Linux man-pages 6.20, dated 2026-02-08. read it, love it, move your pages responsibly ๐ง๐โจ
๐ฆ 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-2-para
- Copyright 2006, Silicon Graphics, Inc
- Copyright 2009, Intel Corp
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms