forked from mirrors/linux
		
	 734c15700c
			
		
	
	
		734c15700c
		
	
	
	
	
		
			
			Abhishek reported that after patch [1], hotplug operations are taking
roughly double the expected time.  [2]
The reason behind is that the CPU callbacks that
migrate_on_reclaim_init() sets always call set_migration_target_nodes()
whenever a CPU is brought up/down.
But we only care about numa nodes going from having cpus to become
cpuless, and vice versa, as that influences the demotion_target order.
We do already have two CPU callbacks (vmstat_cpu_online() and
vmstat_cpu_dead()) that check exactly that, so get rid of the CPU
callbacks in migrate_on_reclaim_init() and only call
set_migration_target_nodes() from vmstat_cpu_{dead,online}() whenever a
numa node change its N_CPU state.
[1] https://lore.kernel.org/linux-mm/20210721063926.3024591-2-ying.huang@intel.com/
[2] https://lore.kernel.org/linux-mm/eb438ddd-2919-73d4-bd9f-b7eecdd9577a@linux.vnet.ibm.com/
[osalvador@suse.de: add feedback from Huang Ying]
  Link: https://lkml.kernel.org/r/20220314150945.12694-1-osalvador@suse.de
Link: https://lkml.kernel.org/r/20220310120749.23077-1-osalvador@suse.de
Fixes: 884a6e5d1f ("mm/migrate: update node demotion order on hotplug events")
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Tested-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reported-by: Abhishek Goel <huntbag@linux.vnet.ibm.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: "Huang, Ying" <ying.huang@intel.com>
Cc: Abhishek Goel <huntbag@linux.vnet.ibm.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
		
	
			
		
			
				
	
	
		
			186 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0 */
 | |
| #ifndef _LINUX_MIGRATE_H
 | |
| #define _LINUX_MIGRATE_H
 | |
| 
 | |
| #include <linux/mm.h>
 | |
| #include <linux/mempolicy.h>
 | |
| #include <linux/migrate_mode.h>
 | |
| #include <linux/hugetlb.h>
 | |
| 
 | |
| typedef struct page *new_page_t(struct page *page, unsigned long private);
 | |
| typedef void free_page_t(struct page *page, unsigned long private);
 | |
| 
 | |
| struct migration_target_control;
 | |
| 
 | |
| /*
 | |
|  * Return values from addresss_space_operations.migratepage():
 | |
|  * - negative errno on page migration failure;
 | |
|  * - zero on page migration success;
 | |
|  */
 | |
| #define MIGRATEPAGE_SUCCESS		0
 | |
| 
 | |
| /* Defined in mm/debug.c: */
 | |
| extern const char *migrate_reason_names[MR_TYPES];
 | |
| 
 | |
| #ifdef CONFIG_MIGRATION
 | |
| 
 | |
| extern void putback_movable_pages(struct list_head *l);
 | |
| extern int migrate_page(struct address_space *mapping,
 | |
| 			struct page *newpage, struct page *page,
 | |
| 			enum migrate_mode mode);
 | |
| extern int migrate_pages(struct list_head *l, new_page_t new, free_page_t free,
 | |
| 		unsigned long private, enum migrate_mode mode, int reason,
 | |
| 		unsigned int *ret_succeeded);
 | |
| extern struct page *alloc_migration_target(struct page *page, unsigned long private);
 | |
| extern int isolate_movable_page(struct page *page, isolate_mode_t mode);
 | |
| 
 | |
| extern void migrate_page_states(struct page *newpage, struct page *page);
 | |
| extern void migrate_page_copy(struct page *newpage, struct page *page);
 | |
| extern int migrate_huge_page_move_mapping(struct address_space *mapping,
 | |
| 				  struct page *newpage, struct page *page);
 | |
| extern int migrate_page_move_mapping(struct address_space *mapping,
 | |
| 		struct page *newpage, struct page *page, int extra_count);
 | |
| void migration_entry_wait_on_locked(swp_entry_t entry, pte_t *ptep,
 | |
| 				spinlock_t *ptl);
 | |
| void folio_migrate_flags(struct folio *newfolio, struct folio *folio);
 | |
| void folio_migrate_copy(struct folio *newfolio, struct folio *folio);
 | |
| int folio_migrate_mapping(struct address_space *mapping,
 | |
| 		struct folio *newfolio, struct folio *folio, int extra_count);
 | |
| 
 | |
| extern bool numa_demotion_enabled;
 | |
| extern void migrate_on_reclaim_init(void);
 | |
| #ifdef CONFIG_HOTPLUG_CPU
 | |
| extern void set_migration_target_nodes(void);
 | |
| #else
 | |
| static inline void set_migration_target_nodes(void) {}
 | |
| #endif
 | |
| #else
 | |
| 
 | |
| static inline void set_migration_target_nodes(void) {}
 | |
| 
 | |
| static inline void putback_movable_pages(struct list_head *l) {}
 | |
| static inline int migrate_pages(struct list_head *l, new_page_t new,
 | |
| 		free_page_t free, unsigned long private, enum migrate_mode mode,
 | |
| 		int reason, unsigned int *ret_succeeded)
 | |
| 	{ return -ENOSYS; }
 | |
| static inline struct page *alloc_migration_target(struct page *page,
 | |
| 		unsigned long private)
 | |
| 	{ return NULL; }
 | |
| static inline int isolate_movable_page(struct page *page, isolate_mode_t mode)
 | |
| 	{ return -EBUSY; }
 | |
| 
 | |
| static inline void migrate_page_states(struct page *newpage, struct page *page)
 | |
| {
 | |
| }
 | |
| 
 | |
| static inline void migrate_page_copy(struct page *newpage,
 | |
| 				     struct page *page) {}
 | |
| 
 | |
| static inline int migrate_huge_page_move_mapping(struct address_space *mapping,
 | |
| 				  struct page *newpage, struct page *page)
 | |
| {
 | |
| 	return -ENOSYS;
 | |
| }
 | |
| 
 | |
| #define numa_demotion_enabled	false
 | |
| #endif /* CONFIG_MIGRATION */
 | |
| 
 | |
| #ifdef CONFIG_COMPACTION
 | |
| extern int PageMovable(struct page *page);
 | |
| extern void __SetPageMovable(struct page *page, struct address_space *mapping);
 | |
| extern void __ClearPageMovable(struct page *page);
 | |
| #else
 | |
| static inline int PageMovable(struct page *page) { return 0; }
 | |
| static inline void __SetPageMovable(struct page *page,
 | |
| 				struct address_space *mapping)
 | |
| {
 | |
| }
 | |
| static inline void __ClearPageMovable(struct page *page)
 | |
| {
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef CONFIG_NUMA_BALANCING
 | |
| extern int migrate_misplaced_page(struct page *page,
 | |
| 				  struct vm_area_struct *vma, int node);
 | |
| #else
 | |
| static inline int migrate_misplaced_page(struct page *page,
 | |
| 					 struct vm_area_struct *vma, int node)
 | |
| {
 | |
| 	return -EAGAIN; /* can't migrate now */
 | |
| }
 | |
| #endif /* CONFIG_NUMA_BALANCING */
 | |
| 
 | |
| #ifdef CONFIG_MIGRATION
 | |
| 
 | |
| /*
 | |
|  * Watch out for PAE architecture, which has an unsigned long, and might not
 | |
|  * have enough bits to store all physical address and flags. So far we have
 | |
|  * enough room for all our flags.
 | |
|  */
 | |
| #define MIGRATE_PFN_VALID	(1UL << 0)
 | |
| #define MIGRATE_PFN_MIGRATE	(1UL << 1)
 | |
| #define MIGRATE_PFN_WRITE	(1UL << 3)
 | |
| #define MIGRATE_PFN_SHIFT	6
 | |
| 
 | |
| static inline struct page *migrate_pfn_to_page(unsigned long mpfn)
 | |
| {
 | |
| 	if (!(mpfn & MIGRATE_PFN_VALID))
 | |
| 		return NULL;
 | |
| 	return pfn_to_page(mpfn >> MIGRATE_PFN_SHIFT);
 | |
| }
 | |
| 
 | |
| static inline unsigned long migrate_pfn(unsigned long pfn)
 | |
| {
 | |
| 	return (pfn << MIGRATE_PFN_SHIFT) | MIGRATE_PFN_VALID;
 | |
| }
 | |
| 
 | |
| enum migrate_vma_direction {
 | |
| 	MIGRATE_VMA_SELECT_SYSTEM = 1 << 0,
 | |
| 	MIGRATE_VMA_SELECT_DEVICE_PRIVATE = 1 << 1,
 | |
| };
 | |
| 
 | |
| struct migrate_vma {
 | |
| 	struct vm_area_struct	*vma;
 | |
| 	/*
 | |
| 	 * Both src and dst array must be big enough for
 | |
| 	 * (end - start) >> PAGE_SHIFT entries.
 | |
| 	 *
 | |
| 	 * The src array must not be modified by the caller after
 | |
| 	 * migrate_vma_setup(), and must not change the dst array after
 | |
| 	 * migrate_vma_pages() returns.
 | |
| 	 */
 | |
| 	unsigned long		*dst;
 | |
| 	unsigned long		*src;
 | |
| 	unsigned long		cpages;
 | |
| 	unsigned long		npages;
 | |
| 	unsigned long		start;
 | |
| 	unsigned long		end;
 | |
| 
 | |
| 	/*
 | |
| 	 * Set to the owner value also stored in page->pgmap->owner for
 | |
| 	 * migrating out of device private memory. The flags also need to
 | |
| 	 * be set to MIGRATE_VMA_SELECT_DEVICE_PRIVATE.
 | |
| 	 * The caller should always set this field when using mmu notifier
 | |
| 	 * callbacks to avoid device MMU invalidations for device private
 | |
| 	 * pages that are not being migrated.
 | |
| 	 */
 | |
| 	void			*pgmap_owner;
 | |
| 	unsigned long		flags;
 | |
| };
 | |
| 
 | |
| int migrate_vma_setup(struct migrate_vma *args);
 | |
| void migrate_vma_pages(struct migrate_vma *migrate);
 | |
| void migrate_vma_finalize(struct migrate_vma *migrate);
 | |
| int next_demotion_node(int node);
 | |
| 
 | |
| #else /* CONFIG_MIGRATION disabled: */
 | |
| 
 | |
| static inline int next_demotion_node(int node)
 | |
| {
 | |
| 	return NUMA_NO_NODE;
 | |
| }
 | |
| 
 | |
| #endif /* CONFIG_MIGRATION */
 | |
| 
 | |
| #endif /* _LINUX_MIGRATE_H */
 |