162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/mm/mmzone.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * management codes for pgdats, zones and page flags 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/stddef.h> 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/mmzone.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistruct pglist_data *first_online_pgdat(void) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci return NODE_DATA(first_online_node); 1662306a36Sopenharmony_ci} 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct pglist_data *next_online_pgdat(struct pglist_data *pgdat) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci int nid = next_online_node(pgdat->node_id); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (nid == MAX_NUMNODES) 2362306a36Sopenharmony_ci return NULL; 2462306a36Sopenharmony_ci return NODE_DATA(nid); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * next_zone - helper magic for for_each_zone() 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistruct zone *next_zone(struct zone *zone) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci pg_data_t *pgdat = zone->zone_pgdat; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (zone < pgdat->node_zones + MAX_NR_ZONES - 1) 3562306a36Sopenharmony_ci zone++; 3662306a36Sopenharmony_ci else { 3762306a36Sopenharmony_ci pgdat = next_online_pgdat(pgdat); 3862306a36Sopenharmony_ci if (pgdat) 3962306a36Sopenharmony_ci zone = pgdat->node_zones; 4062306a36Sopenharmony_ci else 4162306a36Sopenharmony_ci zone = NULL; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci return zone; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic inline int zref_in_nodemask(struct zoneref *zref, nodemask_t *nodes) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci#ifdef CONFIG_NUMA 4962306a36Sopenharmony_ci return node_isset(zonelist_node_idx(zref), *nodes); 5062306a36Sopenharmony_ci#else 5162306a36Sopenharmony_ci return 1; 5262306a36Sopenharmony_ci#endif /* CONFIG_NUMA */ 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* Returns the next zone at or below highest_zoneidx in a zonelist */ 5662306a36Sopenharmony_cistruct zoneref *__next_zones_zonelist(struct zoneref *z, 5762306a36Sopenharmony_ci enum zone_type highest_zoneidx, 5862306a36Sopenharmony_ci nodemask_t *nodes) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci /* 6162306a36Sopenharmony_ci * Find the next suitable zone to use for the allocation. 6262306a36Sopenharmony_ci * Only filter based on nodemask if it's set 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci if (unlikely(nodes == NULL)) 6562306a36Sopenharmony_ci while (zonelist_zone_idx(z) > highest_zoneidx) 6662306a36Sopenharmony_ci z++; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci while (zonelist_zone_idx(z) > highest_zoneidx || 6962306a36Sopenharmony_ci (z->zone && !zref_in_nodemask(z, nodes))) 7062306a36Sopenharmony_ci z++; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return z; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_civoid lruvec_init(struct lruvec *lruvec) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci enum lru_list lru; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci memset(lruvec, 0, sizeof(struct lruvec)); 8062306a36Sopenharmony_ci spin_lock_init(&lruvec->lru_lock); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci for_each_lru(lru) 8362306a36Sopenharmony_ci INIT_LIST_HEAD(&lruvec->lists[lru]); 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * The "Unevictable LRU" is imaginary: though its size is maintained, 8662306a36Sopenharmony_ci * it is never scanned, and unevictable pages are not threaded on it 8762306a36Sopenharmony_ci * (so that their lru fields can be reused to hold mlock_count). 8862306a36Sopenharmony_ci * Poison its list head, so that any operations on it would crash. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci list_del(&lruvec->lists[LRU_UNEVICTABLE]); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci lru_gen_init_lruvec(lruvec); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) 9662306a36Sopenharmony_ciint page_cpupid_xchg_last(struct page *page, int cpupid) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci unsigned long old_flags, flags; 9962306a36Sopenharmony_ci int last_cpupid; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci old_flags = READ_ONCE(page->flags); 10262306a36Sopenharmony_ci do { 10362306a36Sopenharmony_ci flags = old_flags; 10462306a36Sopenharmony_ci last_cpupid = (flags >> LAST_CPUPID_PGSHIFT) & LAST_CPUPID_MASK; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci flags &= ~(LAST_CPUPID_MASK << LAST_CPUPID_PGSHIFT); 10762306a36Sopenharmony_ci flags |= (cpupid & LAST_CPUPID_MASK) << LAST_CPUPID_PGSHIFT; 10862306a36Sopenharmony_ci } while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags))); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return last_cpupid; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci#endif 113