The previous patch teaches get_any_page() to return -ENOTRECOVERABLE
for stable unhandlable kernel pages (PG_reserved, slab, page tables,
large-kmalloc).  memory_failure() still folds every negative return
into MF_MSG_GET_HWPOISON, so callers that want to react to the
unrecoverable cases (a panic option, smarter logging) cannot tell
them apart from transient page-allocator races.

Turn the post-call branch into a switch over the get_hwpoison_page()
return code: map -ENOTRECOVERABLE to MF_MSG_KERNEL and any other
negative return to MF_MSG_GET_HWPOISON.  case 0 keeps the existing
free-buddy / kernel-high-order handling and case 1 falls through to
the rest of memory_failure() unchanged.

The MF_MSG_KERNEL label and tracepoint string are kept as
"reserved kernel page" to avoid breaking userspace tools that match
on those literals; the enum value still adequately tags the failure
even though it now also covers slab, page tables and large-kmalloc
pages.

Suggested-by: David Hildenbrand <[email protected]>
Signed-off-by: Breno Leitao <[email protected]>
---
 mm/memory-failure.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 8f63bdfeff8f..14c0a958638c 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -2426,7 +2426,8 @@ int memory_failure(unsigned long pfn, int flags)
         * that may make page_ref_freeze()/page_ref_unfreeze() mismatch.
         */
        res = get_hwpoison_page(p, flags);
-       if (!res) {
+       switch (res) {
+       case 0:
                if (is_free_buddy_page(p)) {
                        if (take_page_off_buddy(p)) {
                                page_ref_inc(p);
@@ -2445,7 +2446,19 @@ int memory_failure(unsigned long pfn, int flags)
                        res = action_result(pfn, MF_MSG_KERNEL_HIGH_ORDER, 
MF_IGNORED);
                }
                goto unlock_mutex;
-       } else if (res < 0) {
+       case 1:
+               /* Got a refcount on a handlable page. */
+               break;
+       case -ENOTRECOVERABLE:
+               /*
+                * Stable unhandlable kernel-owned page (PG_reserved,
+                * slab, page tables, large-kmalloc).
+                * No recovery possible.
+                */
+               res = action_result(pfn, MF_MSG_KERNEL, MF_IGNORED);
+               goto unlock_mutex;
+       default:
+               /* Transient lifecycle race with the page allocator. */
                res = action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED);
                goto unlock_mutex;
        }

-- 
2.54.0


Reply via email to