|
@@ -441,6 +441,54 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
|
|
|
return MIGRATEPAGE_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Gigantic pages are so large that we do not guarantee that page++ pointer
|
|
|
+ * arithmetic will work across the entire page. We need something more
|
|
|
+ * specialized.
|
|
|
+ */
|
|
|
+static void __copy_gigantic_page(struct page *dst, struct page *src,
|
|
|
+ int nr_pages)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct page *dst_base = dst;
|
|
|
+ struct page *src_base = src;
|
|
|
+
|
|
|
+ for (i = 0; i < nr_pages; ) {
|
|
|
+ cond_resched();
|
|
|
+ copy_highpage(dst, src);
|
|
|
+
|
|
|
+ i++;
|
|
|
+ dst = mem_map_next(dst, dst_base, i);
|
|
|
+ src = mem_map_next(src, src_base, i);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void copy_huge_page(struct page *dst, struct page *src)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int nr_pages;
|
|
|
+
|
|
|
+ if (PageHuge(src)) {
|
|
|
+ /* hugetlbfs page */
|
|
|
+ struct hstate *h = page_hstate(src);
|
|
|
+ nr_pages = pages_per_huge_page(h);
|
|
|
+
|
|
|
+ if (unlikely(nr_pages > MAX_ORDER_NR_PAGES)) {
|
|
|
+ __copy_gigantic_page(dst, src, nr_pages);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* thp page */
|
|
|
+ BUG_ON(!PageTransHuge(src));
|
|
|
+ nr_pages = hpage_nr_pages(src);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < nr_pages; i++) {
|
|
|
+ cond_resched();
|
|
|
+ copy_highpage(dst + i, src + i);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Copy the page to its new location
|
|
|
*/
|