mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	- Rewrite how munlock works to massively reduce the contention
    on i_mmap_rwsem (Hugh Dickins):
    https://lore.kernel.org/linux-mm/8e4356d-9622-a7f0-b2c-f116b5f2efea@google.com/
  - Sort out the page refcount mess for ZONE_DEVICE pages (Christoph Hellwig):
    https://lore.kernel.org/linux-mm/20220210072828.2930359-1-hch@lst.de/
  - Convert GUP to use folios and make pincount available for order-1
    pages. (Matthew Wilcox)
  - Convert a few more truncation functions to use folios (Matthew Wilcox)
  - Convert page_vma_mapped_walk to use PFNs instead of pages (Matthew Wilcox)
  - Convert rmap_walk to use folios (Matthew Wilcox)
  - Convert most of shrink_page_list() to use a folio (Matthew Wilcox)
  - Add support for creating large folios in readahead (Matthew Wilcox)
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEejHryeLBw/spnjHrDpNsjXcpgj4FAmI4ucgACgkQDpNsjXcp
 gj69Wgf6AwqwmO5Tmy+fLScDPqWxmXJofbocae1kyoGHf7Ui91OK4U2j6IpvAr+g
 P/vLIK+JAAcTQcrSCjymuEkf4HkGZOR03QQn7maPIEe4eLrZRQDEsmHC1L9gpeJp
 s/GMvDWiGE0Tnxu0EOzfVi/yT+qjIl/S8VvqtCoJv1HdzxitZ7+1RDuqImaMC5MM
 Qi3uHag78vLmCltLXpIOdpgZhdZexCdL2Y/1npf+b6FVkAJRRNUnA0gRbS7YpoVp
 CbxEJcmAl9cpJLuj5i5kIfS9trr+/QcvbUlzRxh4ggC58iqnmF2V09l2MJ7YU3XL
 v1O/Elq4lRhXninZFQEm9zjrri7LDQ==
 =n9Ad
 -----END PGP SIGNATURE-----
Merge tag 'folio-5.18c' of git://git.infradead.org/users/willy/pagecache
Pull folio updates from Matthew Wilcox:
 - Rewrite how munlock works to massively reduce the contention on
   i_mmap_rwsem (Hugh Dickins):
     https://lore.kernel.org/linux-mm/8e4356d-9622-a7f0-b2c-f116b5f2efea@google.com/
 - Sort out the page refcount mess for ZONE_DEVICE pages (Christoph
   Hellwig):
     https://lore.kernel.org/linux-mm/20220210072828.2930359-1-hch@lst.de/
 - Convert GUP to use folios and make pincount available for order-1
   pages. (Matthew Wilcox)
 - Convert a few more truncation functions to use folios (Matthew
   Wilcox)
 - Convert page_vma_mapped_walk to use PFNs instead of pages (Matthew
   Wilcox)
 - Convert rmap_walk to use folios (Matthew Wilcox)
 - Convert most of shrink_page_list() to use a folio (Matthew Wilcox)
 - Add support for creating large folios in readahead (Matthew Wilcox)
* tag 'folio-5.18c' of git://git.infradead.org/users/willy/pagecache: (114 commits)
  mm/damon: minor cleanup for damon_pa_young
  selftests/vm/transhuge-stress: Support file-backed PMD folios
  mm/filemap: Support VM_HUGEPAGE for file mappings
  mm/readahead: Switch to page_cache_ra_order
  mm/readahead: Align file mappings for non-DAX
  mm/readahead: Add large folio readahead
  mm: Support arbitrary THP sizes
  mm: Make large folios depend on THP
  mm: Fix READ_ONLY_THP warning
  mm/filemap: Allow large folios to be added to the page cache
  mm: Turn can_split_huge_page() into can_split_folio()
  mm/vmscan: Convert pageout() to take a folio
  mm/vmscan: Turn page_check_references() into folio_check_references()
  mm/vmscan: Account large folios correctly
  mm/vmscan: Optimise shrink_page_list for non-PMD-sized folios
  mm/vmscan: Free non-shmem folios without splitting them
  mm/rmap: Constify the rmap_walk_control argument
  mm/rmap: Convert rmap_walk() to take a folio
  mm: Turn page_anon_vma() into folio_anon_vma()
  mm/rmap: Turn page_lock_anon_vma_read() into folio_lock_anon_vma_read()
  ...
		
	
			
		
			
				
	
	
		
			110 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			110 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * linux/mm/mmzone.c
 | 
						|
 *
 | 
						|
 * management codes for pgdats, zones and page flags
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include <linux/stddef.h>
 | 
						|
#include <linux/mm.h>
 | 
						|
#include <linux/mmzone.h>
 | 
						|
 | 
						|
struct pglist_data *first_online_pgdat(void)
 | 
						|
{
 | 
						|
	return NODE_DATA(first_online_node);
 | 
						|
}
 | 
						|
 | 
						|
struct pglist_data *next_online_pgdat(struct pglist_data *pgdat)
 | 
						|
{
 | 
						|
	int nid = next_online_node(pgdat->node_id);
 | 
						|
 | 
						|
	if (nid == MAX_NUMNODES)
 | 
						|
		return NULL;
 | 
						|
	return NODE_DATA(nid);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * next_zone - helper magic for for_each_zone()
 | 
						|
 */
 | 
						|
struct zone *next_zone(struct zone *zone)
 | 
						|
{
 | 
						|
	pg_data_t *pgdat = zone->zone_pgdat;
 | 
						|
 | 
						|
	if (zone < pgdat->node_zones + MAX_NR_ZONES - 1)
 | 
						|
		zone++;
 | 
						|
	else {
 | 
						|
		pgdat = next_online_pgdat(pgdat);
 | 
						|
		if (pgdat)
 | 
						|
			zone = pgdat->node_zones;
 | 
						|
		else
 | 
						|
			zone = NULL;
 | 
						|
	}
 | 
						|
	return zone;
 | 
						|
}
 | 
						|
 | 
						|
static inline int zref_in_nodemask(struct zoneref *zref, nodemask_t *nodes)
 | 
						|
{
 | 
						|
#ifdef CONFIG_NUMA
 | 
						|
	return node_isset(zonelist_node_idx(zref), *nodes);
 | 
						|
#else
 | 
						|
	return 1;
 | 
						|
#endif /* CONFIG_NUMA */
 | 
						|
}
 | 
						|
 | 
						|
/* Returns the next zone at or below highest_zoneidx in a zonelist */
 | 
						|
struct zoneref *__next_zones_zonelist(struct zoneref *z,
 | 
						|
					enum zone_type highest_zoneidx,
 | 
						|
					nodemask_t *nodes)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	 * Find the next suitable zone to use for the allocation.
 | 
						|
	 * Only filter based on nodemask if it's set
 | 
						|
	 */
 | 
						|
	if (unlikely(nodes == NULL))
 | 
						|
		while (zonelist_zone_idx(z) > highest_zoneidx)
 | 
						|
			z++;
 | 
						|
	else
 | 
						|
		while (zonelist_zone_idx(z) > highest_zoneidx ||
 | 
						|
				(z->zone && !zref_in_nodemask(z, nodes)))
 | 
						|
			z++;
 | 
						|
 | 
						|
	return z;
 | 
						|
}
 | 
						|
 | 
						|
void lruvec_init(struct lruvec *lruvec)
 | 
						|
{
 | 
						|
	enum lru_list lru;
 | 
						|
 | 
						|
	memset(lruvec, 0, sizeof(struct lruvec));
 | 
						|
	spin_lock_init(&lruvec->lru_lock);
 | 
						|
 | 
						|
	for_each_lru(lru)
 | 
						|
		INIT_LIST_HEAD(&lruvec->lists[lru]);
 | 
						|
	/*
 | 
						|
	 * The "Unevictable LRU" is imaginary: though its size is maintained,
 | 
						|
	 * it is never scanned, and unevictable pages are not threaded on it
 | 
						|
	 * (so that their lru fields can be reused to hold mlock_count).
 | 
						|
	 * Poison its list head, so that any operations on it would crash.
 | 
						|
	 */
 | 
						|
	list_del(&lruvec->lists[LRU_UNEVICTABLE]);
 | 
						|
}
 | 
						|
 | 
						|
#if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS)
 | 
						|
int page_cpupid_xchg_last(struct page *page, int cpupid)
 | 
						|
{
 | 
						|
	unsigned long old_flags, flags;
 | 
						|
	int last_cpupid;
 | 
						|
 | 
						|
	old_flags = READ_ONCE(page->flags);
 | 
						|
	do {
 | 
						|
		flags = old_flags;
 | 
						|
		last_cpupid = (flags >> LAST_CPUPID_PGSHIFT) & LAST_CPUPID_MASK;
 | 
						|
 | 
						|
		flags &= ~(LAST_CPUPID_MASK << LAST_CPUPID_PGSHIFT);
 | 
						|
		flags |= (cpupid & LAST_CPUPID_MASK) << LAST_CPUPID_PGSHIFT;
 | 
						|
	} while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags)));
 | 
						|
 | 
						|
	return last_cpupid;
 | 
						|
}
 | 
						|
#endif
 |