|
@@ -2390,6 +2390,21 @@ int page_trans_huge_mapcount(struct page *page, int *total_mapcount)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Racy check whether the huge page can be split */
|
|
|
|
+bool can_split_huge_page(struct page *page, int *pextra_pins)
|
|
|
|
+{
|
|
|
|
+ int extra_pins;
|
|
|
|
+
|
|
|
|
+ /* Additional pins from radix tree */
|
|
|
|
+ if (PageAnon(page))
|
|
|
|
+ extra_pins = PageSwapCache(page) ? HPAGE_PMD_NR : 0;
|
|
|
|
+ else
|
|
|
|
+ extra_pins = HPAGE_PMD_NR;
|
|
|
|
+ if (pextra_pins)
|
|
|
|
+ *pextra_pins = extra_pins;
|
|
|
|
+ return total_mapcount(page) == page_count(page) - extra_pins - 1;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* This function splits huge page into normal pages. @page can point to any
|
|
* This function splits huge page into normal pages. @page can point to any
|
|
* subpage of huge page to split. Split doesn't change the position of @page.
|
|
* subpage of huge page to split. Split doesn't change the position of @page.
|
|
@@ -2437,7 +2452,6 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
|
|
ret = -EBUSY;
|
|
ret = -EBUSY;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
- extra_pins = PageSwapCache(page) ? HPAGE_PMD_NR : 0;
|
|
|
|
mapping = NULL;
|
|
mapping = NULL;
|
|
anon_vma_lock_write(anon_vma);
|
|
anon_vma_lock_write(anon_vma);
|
|
} else {
|
|
} else {
|
|
@@ -2449,8 +2463,6 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Addidional pins from radix tree */
|
|
|
|
- extra_pins = HPAGE_PMD_NR;
|
|
|
|
anon_vma = NULL;
|
|
anon_vma = NULL;
|
|
i_mmap_lock_read(mapping);
|
|
i_mmap_lock_read(mapping);
|
|
}
|
|
}
|
|
@@ -2459,7 +2471,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
|
|
* Racy check if we can split the page, before freeze_page() will
|
|
* Racy check if we can split the page, before freeze_page() will
|
|
* split PMDs
|
|
* split PMDs
|
|
*/
|
|
*/
|
|
- if (total_mapcount(head) != page_count(head) - extra_pins - 1) {
|
|
|
|
|
|
+ if (!can_split_huge_page(head, &extra_pins)) {
|
|
ret = -EBUSY;
|
|
ret = -EBUSY;
|
|
goto out_unlock;
|
|
goto out_unlock;
|
|
}
|
|
}
|