Commit 19fc7bed authored by Joonsoo Kim's avatar Joonsoo Kim Committed by Linus Torvalds

mm/migrate: introduce a standard migration target allocation function

There are some similar functions for migration target allocation.  Since
there is no fundamental difference, it's better to keep just one rather
than keeping all variants.  This patch implements base migration target
allocation function.  In the following patches, variants will be converted
to use this function.

Changes should be mechanical, but, unfortunately, there are some
differences.  First, some callers' nodemask is assgined to NULL since NULL
nodemask will be considered as all available nodes, that is,
&node_states[N_MEMORY].  Second, for hugetlb page allocation, gfp_mask is
redefined as regular hugetlb allocation gfp_mask plus __GFP_THISNODE if
user provided gfp_mask has it.  This is because future caller of this
function requires to set this node constaint.  Lastly, if provided nodeid
is NUMA_NO_NODE, nodeid is set up to the node where migration source
lives.  It helps to remove simple wrappers for setting up the nodeid.

Note that PageHighmem() call in previous function is changed to open-code
"is_highmem_idx()" since it provides more readability.

[akpm@linux-foundation.org: tweak patch title, per Vlastimil]
[akpm@linux-foundation.org: fix typo in comment]
Signed-off-by: default avatarJoonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Acked-by: default avatarVlastimil Babka <vbabka@suse.cz>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Roman Gushchin <guro@fb.com>
Link: http://lkml.kernel.org/r/1594622517-20681-6-git-send-email-iamjoonsoo.kim@lge.comSigned-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 9933a0c8
...@@ -703,6 +703,16 @@ static inline gfp_t htlb_alloc_mask(struct hstate *h) ...@@ -703,6 +703,16 @@ static inline gfp_t htlb_alloc_mask(struct hstate *h)
return GFP_HIGHUSER; return GFP_HIGHUSER;
} }
static inline gfp_t htlb_modify_alloc_mask(struct hstate *h, gfp_t gfp_mask)
{
gfp_t modified_mask = htlb_alloc_mask(h);
/* Some callers might want to enforce node */
modified_mask |= (gfp_mask & __GFP_THISNODE);
return modified_mask;
}
static inline spinlock_t *huge_pte_lockptr(struct hstate *h, static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
struct mm_struct *mm, pte_t *pte) struct mm_struct *mm, pte_t *pte)
{ {
...@@ -890,6 +900,11 @@ static inline gfp_t htlb_alloc_mask(struct hstate *h) ...@@ -890,6 +900,11 @@ static inline gfp_t htlb_alloc_mask(struct hstate *h)
return 0; return 0;
} }
static inline gfp_t htlb_modify_alloc_mask(struct hstate *h, gfp_t gfp_mask)
{
return 0;
}
static inline spinlock_t *huge_pte_lockptr(struct hstate *h, static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
struct mm_struct *mm, pte_t *pte) struct mm_struct *mm, pte_t *pte)
{ {
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
typedef struct page *new_page_t(struct page *page, unsigned long private); typedef struct page *new_page_t(struct page *page, unsigned long private);
typedef void free_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(): * Return values from addresss_space_operations.migratepage():
* - negative errno on page migration failure; * - negative errno on page migration failure;
...@@ -39,8 +41,7 @@ extern int migrate_page(struct address_space *mapping, ...@@ -39,8 +41,7 @@ extern int migrate_page(struct address_space *mapping,
enum migrate_mode mode); enum migrate_mode mode);
extern int migrate_pages(struct list_head *l, new_page_t new, free_page_t free, 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 long private, enum migrate_mode mode, int reason);
extern struct page *new_page_nodemask(struct page *page, extern struct page *alloc_migration_target(struct page *page, unsigned long private);
int preferred_nid, nodemask_t *nodemask);
extern int isolate_movable_page(struct page *page, isolate_mode_t mode); extern int isolate_movable_page(struct page *page, isolate_mode_t mode);
extern void putback_movable_page(struct page *page); extern void putback_movable_page(struct page *page);
...@@ -59,8 +60,8 @@ static inline int migrate_pages(struct list_head *l, new_page_t new, ...@@ -59,8 +60,8 @@ static inline int migrate_pages(struct list_head *l, new_page_t new,
free_page_t free, unsigned long private, enum migrate_mode mode, free_page_t free, unsigned long private, enum migrate_mode mode,
int reason) int reason)
{ return -ENOSYS; } { return -ENOSYS; }
static inline struct page *new_page_nodemask(struct page *page, static inline struct page *alloc_migration_target(struct page *page,
int preferred_nid, nodemask_t *nodemask) unsigned long private)
{ return NULL; } { return NULL; }
static inline int isolate_movable_page(struct page *page, isolate_mode_t mode) static inline int isolate_movable_page(struct page *page, isolate_mode_t mode)
{ return -EBUSY; } { return -EBUSY; }
......
...@@ -614,4 +614,11 @@ static inline bool is_migrate_highatomic_page(struct page *page) ...@@ -614,4 +614,11 @@ static inline bool is_migrate_highatomic_page(struct page *page)
void setup_zone_pageset(struct zone *zone); void setup_zone_pageset(struct zone *zone);
extern struct page *alloc_new_node_page(struct page *page, unsigned long node); extern struct page *alloc_new_node_page(struct page *page, unsigned long node);
struct migration_target_control {
int nid; /* preferred node id */
nodemask_t *nmask;
gfp_t gfp_mask;
};
#endif /* __MM_INTERNAL_H */ #endif /* __MM_INTERNAL_H */
...@@ -1648,9 +1648,12 @@ EXPORT_SYMBOL(unpoison_memory); ...@@ -1648,9 +1648,12 @@ EXPORT_SYMBOL(unpoison_memory);
static struct page *new_page(struct page *p, unsigned long private) static struct page *new_page(struct page *p, unsigned long private)
{ {
int nid = page_to_nid(p); struct migration_target_control mtc = {
.nid = page_to_nid(p),
.gfp_mask = GFP_USER | __GFP_MOVABLE | __GFP_RETRY_MAYFAIL,
};
return new_page_nodemask(p, nid, &node_states[N_MEMORY]); return alloc_migration_target(p, (unsigned long)&mtc);
} }
/* /*
......
...@@ -1276,19 +1276,23 @@ static int scan_movable_pages(unsigned long start, unsigned long end, ...@@ -1276,19 +1276,23 @@ static int scan_movable_pages(unsigned long start, unsigned long end,
static struct page *new_node_page(struct page *page, unsigned long private) static struct page *new_node_page(struct page *page, unsigned long private)
{ {
int nid = page_to_nid(page);
nodemask_t nmask = node_states[N_MEMORY]; nodemask_t nmask = node_states[N_MEMORY];
struct migration_target_control mtc = {
.nid = page_to_nid(page),
.nmask = &nmask,
.gfp_mask = GFP_USER | __GFP_MOVABLE | __GFP_RETRY_MAYFAIL,
};
/* /*
* try to allocate from a different node but reuse this node if there * try to allocate from a different node but reuse this node if there
* are no other online nodes to be used (e.g. we are offlining a part * are no other online nodes to be used (e.g. we are offlining a part
* of the only existing node) * of the only existing node)
*/ */
node_clear(nid, nmask); node_clear(mtc.nid, nmask);
if (nodes_empty(nmask)) if (nodes_empty(nmask))
node_set(nid, nmask); node_set(mtc.nid, nmask);
return new_page_nodemask(page, nid, &nmask); return alloc_migration_target(page, (unsigned long)&mtc);
} }
static int static int
......
...@@ -1538,19 +1538,26 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page, ...@@ -1538,19 +1538,26 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
return rc; return rc;
} }
struct page *new_page_nodemask(struct page *page, struct page *alloc_migration_target(struct page *page, unsigned long private)
int preferred_nid, nodemask_t *nodemask)
{ {
gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE | __GFP_RETRY_MAYFAIL; struct migration_target_control *mtc;
gfp_t gfp_mask;
unsigned int order = 0; unsigned int order = 0;
struct page *new_page = NULL; struct page *new_page = NULL;
int nid;
int zidx;
mtc = (struct migration_target_control *)private;
gfp_mask = mtc->gfp_mask;
nid = mtc->nid;
if (nid == NUMA_NO_NODE)
nid = page_to_nid(page);
if (PageHuge(page)) { if (PageHuge(page)) {
struct hstate *h = page_hstate(compound_head(page)); struct hstate *h = page_hstate(compound_head(page));
gfp_mask = htlb_alloc_mask(h); gfp_mask = htlb_modify_alloc_mask(h, gfp_mask);
return alloc_huge_page_nodemask(h, preferred_nid, return alloc_huge_page_nodemask(h, nid, mtc->nmask, gfp_mask);
nodemask, gfp_mask);
} }
if (PageTransHuge(page)) { if (PageTransHuge(page)) {
...@@ -1562,12 +1569,11 @@ struct page *new_page_nodemask(struct page *page, ...@@ -1562,12 +1569,11 @@ struct page *new_page_nodemask(struct page *page,
gfp_mask |= GFP_TRANSHUGE; gfp_mask |= GFP_TRANSHUGE;
order = HPAGE_PMD_ORDER; order = HPAGE_PMD_ORDER;
} }
zidx = zone_idx(page_zone(page));
if (PageHighMem(page) || (zone_idx(page_zone(page)) == ZONE_MOVABLE)) if (is_highmem_idx(zidx) || zidx == ZONE_MOVABLE)
gfp_mask |= __GFP_HIGHMEM; gfp_mask |= __GFP_HIGHMEM;
new_page = __alloc_pages_nodemask(gfp_mask, order, new_page = __alloc_pages_nodemask(gfp_mask, order, nid, mtc->nmask);
preferred_nid, nodemask);
if (new_page && PageTransHuge(new_page)) if (new_page && PageTransHuge(new_page))
prep_transhuge_page(new_page); prep_transhuge_page(new_page);
......
...@@ -309,7 +309,10 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn, ...@@ -309,7 +309,10 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
struct page *alloc_migrate_target(struct page *page, unsigned long private) struct page *alloc_migrate_target(struct page *page, unsigned long private)
{ {
int nid = page_to_nid(page); struct migration_target_control mtc = {
.nid = page_to_nid(page),
.gfp_mask = GFP_USER | __GFP_MOVABLE | __GFP_RETRY_MAYFAIL,
};
return new_page_nodemask(page, nid, &node_states[N_MEMORY]); return alloc_migration_target(page, (unsigned long)&mtc);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment