diff options
-rw-r--r-- | include/trace/events/huge_memory.h | 3 | ||||
-rw-r--r-- | mm/khugepaged.c | 20 |
2 files changed, 22 insertions, 1 deletions
diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h index 3e6fb05852f9..c84c7af70158 100644 --- a/include/trace/events/huge_memory.h +++ b/include/trace/events/huge_memory.h @@ -36,7 +36,8 @@ EM( SCAN_ALLOC_HUGE_PAGE_FAIL, "alloc_huge_page_failed") \ EM( SCAN_CGROUP_CHARGE_FAIL, "ccgroup_charge_failed") \ EM( SCAN_TRUNCATED, "truncated") \ - EMe(SCAN_PAGE_HAS_PRIVATE, "page_has_private") \ + EM( SCAN_PAGE_HAS_PRIVATE, "page_has_private") \ + EMe(SCAN_STORE_FAILED, "store_failed") #undef EM #undef EMe diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 2c6548cd18a9..3b61cd188f7b 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 @@ -1857,6 +1858,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; } @@ -2009,6 +2019,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 the allocation happened before) + * but let's check for errors (XArray implementation can be + * changed in the future) + */ + WARN_ON_ONCE(xas_error(&xas)); continue; out_unlock: unlock_page(page); @@ -2046,6 +2061,11 @@ out_unlock: /* 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) + */ + WARN_ON_ONCE(xas_error(&xas)); xa_locked: xas_unlock_irq(&xas); xa_unlocked: |