mm/migrate.c

Source file repositories/reference/linux-study-clean/mm/migrate.c

File Facts

System
Linux kernel
Corpus path
mm/migrate.c
Extension
.c
Size
77434 bytes
Lines
2772
Domain
Core OS
Bucket
Memory Management
Inferred role
Core OS: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
		const void __user * __user *, pages,
		const int __user *, nodes,
		int __user *, status, int, flags)
{
	return kernel_move_pages(pid, nr_pages, pages, nodes, status, flags);
}
#endif /* CONFIG_NUMA_MIGRATION */

#ifdef CONFIG_NUMA_BALANCING
/*
 * Returns true if this is a safe migration target node for misplaced NUMA
 * pages. Currently it only checks the watermarks which is crude.
 */
static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
				   unsigned long nr_migrate_pages)
{
	int z;

	for (z = pgdat->nr_zones - 1; z >= 0; z--) {
		struct zone *zone = pgdat->node_zones + z;

		if (!managed_zone(zone))
			continue;

		/* Avoid waking kswapd by allocating pages_to_migrate pages. */
		if (!zone_watermark_ok(zone, 0,
				       high_wmark_pages(zone) +
				       nr_migrate_pages,
				       ZONE_MOVABLE, ALLOC_CMA))
			continue;
		return true;
	}
	return false;
}

static struct folio *alloc_misplaced_dst_folio(struct folio *src,
					   unsigned long data)
{
	int nid = (int) data;
	int order = folio_order(src);
	gfp_t gfp = __GFP_THISNODE;

	if (order > 0)
		gfp |= GFP_TRANSHUGE_LIGHT;
	else {
		gfp |= GFP_HIGHUSER_MOVABLE | __GFP_NOMEMALLOC | __GFP_NORETRY |
			__GFP_NOWARN;
		gfp &= ~__GFP_RECLAIM;
	}
	return __folio_alloc_node(gfp, order, nid);
}

/*
 * Prepare for calling migrate_misplaced_folio() by isolating the folio if
 * permitted. Must be called with the PTL still held.
 */
int migrate_misplaced_folio_prepare(struct folio *folio,
		struct vm_area_struct *vma, int node)
{
	int nr_pages = folio_nr_pages(folio);
	pg_data_t *pgdat = NODE_DATA(node);

	if (folio_is_file_lru(folio)) {
		/*
		 * Do not migrate file folios that are mapped in multiple
		 * processes with execute permissions as they are probably
		 * shared libraries.
		 *
		 * See folio_maybe_mapped_shared() on possible imprecision
		 * when we cannot easily detect if a folio is shared.
		 */
		if ((vma->vm_flags & VM_EXEC) && folio_maybe_mapped_shared(folio))
			return -EACCES;

		/*
		 * Do not migrate dirty folios as not all filesystems can move
		 * dirty folios in MIGRATE_ASYNC mode which is a waste of
		 * cycles.
		 */
		if (folio_test_dirty(folio))
			return -EAGAIN;
	}

	/* Avoid migrating to a node that is nearly full */
	if (!migrate_balanced_pgdat(pgdat, nr_pages)) {
		int z;

		if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING))
			return -EAGAIN;

Annotation

Implementation Notes