summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mm/khugepaged.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index cfa0dba5fd3b..3a494cfa56d2 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -914,6 +914,18 @@ static struct page *khugepaged_alloc_hugepage(bool *wait)
static bool khugepaged_prealloc_page(struct page **hpage, bool *wait)
{
+ /*
+ * If the hpage allocated earlier was briefly exposed in page cache
+ * before collapse_file() failed, it is possible that racing lookups
+ * have not yet completed, and would then be unpleasantly surprised by
+ * finding the hpage reused for the same mapping at a different offset.
+ * Just release the previous allocation if there is any danger of that.
+ */
+ if (*hpage && page_count(*hpage) > 1) {
+ put_page(*hpage);
+ *hpage = NULL;
+ }
+
if (!*hpage)
*hpage = khugepaged_alloc_hugepage(wait);