diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 92e6f56a932d..232b1ac390bd 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -55,6 +55,7 @@ enum scan_result { SCAN_CGROUP_CHARGE_FAIL, SCAN_TRUNCATED, SCAN_PAGE_HAS_PRIVATE, + SCAN_STORE_FAILED, }; #define CREATE_TRACE_POINTS @@ -1840,6 +1841,15 @@ static int collapse_file(struct mm_struct *mm, unsigned long addr, goto xa_locked; } xas_store(&xas, hpage); + if (xas_error(&xas)) { + /* revert shmem_charge performed + * in the previous condition + */ + mapping->nrpages--; + shmem_uncharge(mapping->host, 1); + result = SCAN_STORE_FAILED; + goto xa_locked; + } nr_none++; continue; } @@ -1992,6 +2002,11 @@ static int collapse_file(struct mm_struct *mm, unsigned long addr, /* Finally, replace with the new page. */ xas_store(&xas, hpage); + /* We can't get an ENOMEM here (because it was allocated before) + * but let's check for errors (XArray implementation can be + * changed in the future) + */ + VM_BUG_ON(xas_error(&xas)); continue; out_unlock: unlock_page(page); @@ -2029,6 +2044,11 @@ static int collapse_file(struct mm_struct *mm, unsigned long addr, /* Join all the small entries into a single multi-index entry */ xas_set_order(&xas, start, HPAGE_PMD_ORDER); xas_store(&xas, hpage); + /* Here we can't get an ENOMEM (because entries were + * previously allocated) But let's check for errors + * (XArray implementation can be changed in the future) + */ + VM_BUG_ON(xas_error(&xas)); xa_locked: xas_unlock_irq(&xas); xa_unlocked: