aboutsummaryrefslogtreecommitdiffstats
path: root/mm/migrate.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/migrate.c')
-rw-r--r--mm/migrate.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/mm/migrate.c b/mm/migrate.c
index 482a33d89134..bed48809e5d0 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -178,6 +178,37 @@ out:
178} 178}
179 179
180/* 180/*
181 * Congratulations to trinity for discovering this bug.
182 * mm/fremap.c's remap_file_pages() accepts any range within a single vma to
183 * convert that vma to VM_NONLINEAR; and generic_file_remap_pages() will then
184 * replace the specified range by file ptes throughout (maybe populated after).
185 * If page migration finds a page within that range, while it's still located
186 * by vma_interval_tree rather than lost to i_mmap_nonlinear list, no problem:
187 * zap_pte() clears the temporary migration entry before mmap_sem is dropped.
188 * But if the migrating page is in a part of the vma outside the range to be
189 * remapped, then it will not be cleared, and remove_migration_ptes() needs to
190 * deal with it. Fortunately, this part of the vma is of course still linear,
191 * so we just need to use linear location on the nonlinear list.
192 */
193static int remove_linear_migration_ptes_from_nonlinear(struct page *page,
194 struct address_space *mapping, void *arg)
195{
196 struct vm_area_struct *vma;
197 /* hugetlbfs does not support remap_pages, so no huge pgoff worries */
198 pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
199 unsigned long addr;
200
201 list_for_each_entry(vma,
202 &mapping->i_mmap_nonlinear, shared.nonlinear) {
203
204 addr = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
205 if (addr >= vma->vm_start && addr < vma->vm_end)
206 remove_migration_pte(page, vma, addr, arg);
207 }
208 return SWAP_AGAIN;
209}
210
211/*
181 * Get rid of all migration entries and replace them by 212 * Get rid of all migration entries and replace them by
182 * references to the indicated page. 213 * references to the indicated page.
183 */ 214 */
@@ -186,6 +217,7 @@ static void remove_migration_ptes(struct page *old, struct page *new)
186 struct rmap_walk_control rwc = { 217 struct rmap_walk_control rwc = {
187 .rmap_one = remove_migration_pte, 218 .rmap_one = remove_migration_pte,
188 .arg = old, 219 .arg = old,
220 .file_nonlinear = remove_linear_migration_ptes_from_nonlinear,
189 }; 221 };
190 222
191 rmap_walk(new, &rwc); 223 rmap_walk(new, &rwc);
@@ -1158,7 +1190,7 @@ static struct page *new_page_node(struct page *p, unsigned long private,
1158 pm->node); 1190 pm->node);
1159 else 1191 else
1160 return alloc_pages_exact_node(pm->node, 1192 return alloc_pages_exact_node(pm->node,
1161 GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0); 1193 GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0);
1162} 1194}
1163 1195
1164/* 1196/*
@@ -1544,9 +1576,9 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
1544 struct page *newpage; 1576 struct page *newpage;
1545 1577
1546 newpage = alloc_pages_exact_node(nid, 1578 newpage = alloc_pages_exact_node(nid,
1547 (GFP_HIGHUSER_MOVABLE | GFP_THISNODE | 1579 (GFP_HIGHUSER_MOVABLE |
1548 __GFP_NOMEMALLOC | __GFP_NORETRY | 1580 __GFP_THISNODE | __GFP_NOMEMALLOC |
1549 __GFP_NOWARN) & 1581 __GFP_NORETRY | __GFP_NOWARN) &
1550 ~GFP_IOFS, 0); 1582 ~GFP_IOFS, 0);
1551 1583
1552 return newpage; 1584 return newpage;
@@ -1747,7 +1779,8 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
1747 goto out_dropref; 1779 goto out_dropref;
1748 1780
1749 new_page = alloc_pages_node(node, 1781 new_page = alloc_pages_node(node,
1750 (GFP_TRANSHUGE | GFP_THISNODE) & ~__GFP_WAIT, HPAGE_PMD_ORDER); 1782 (GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_WAIT,
1783 HPAGE_PMD_ORDER);
1751 if (!new_page) 1784 if (!new_page)
1752 goto out_fail; 1785 goto out_fail;
1753 1786