Skip to content

Commit c85106f

Browse files
osalvadorvilardagagregkh
authored andcommitted
mm,swapops: update check in is_pfn_swap_entry for hwpoison entries
commit 07a57a3 upstream. Tony reported that the Machine check recovery was broken in v6.9-rc1, as he was hitting a VM_BUG_ON when injecting uncorrectable memory errors to DRAM. After some more digging and debugging on his side, he realized that this went back to v6.1, with the introduction of 'commit 0d206b5 ("mm/swap: add swp_offset_pfn() to fetch PFN from swap entry")'. That commit, among other things, introduced swp_offset_pfn(), replacing hwpoison_entry_to_pfn() in its favour. The patch also introduced a VM_BUG_ON() check for is_pfn_swap_entry(), but is_pfn_swap_entry() never got updated to cover hwpoison entries, which means that we would hit the VM_BUG_ON whenever we would call swp_offset_pfn() for such entries on environments with CONFIG_DEBUG_VM set. Fix this by updating the check to cover hwpoison entries as well, and update the comment while we are it. Link: https://lkml.kernel.org/r/[email protected] Fixes: 0d206b5 ("mm/swap: add swp_offset_pfn() to fetch PFN from swap entry") Signed-off-by: Oscar Salvador <[email protected]> Reported-by: Tony Luck <[email protected]> Closes: https://lore.kernel.org/all/Zg8kLSl2yAlA3o5D@agluck-desk3/ Tested-by: Tony Luck <[email protected]> Reviewed-by: Peter Xu <[email protected]> Reviewed-by: David Hildenbrand <[email protected]> Acked-by: Miaohe Lin <[email protected]> Cc: <[email protected]> [6.1.x] Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent db01bfb commit c85106f

File tree

1 file changed

+33
-32
lines changed

1 file changed

+33
-32
lines changed

include/linux/swapops.h

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,35 @@ static inline bool is_migration_entry_dirty(swp_entry_t entry)
390390
}
391391
#endif /* CONFIG_MIGRATION */
392392

393+
#ifdef CONFIG_MEMORY_FAILURE
394+
395+
/*
396+
* Support for hardware poisoned pages
397+
*/
398+
static inline swp_entry_t make_hwpoison_entry(struct page *page)
399+
{
400+
BUG_ON(!PageLocked(page));
401+
return swp_entry(SWP_HWPOISON, page_to_pfn(page));
402+
}
403+
404+
static inline int is_hwpoison_entry(swp_entry_t entry)
405+
{
406+
return swp_type(entry) == SWP_HWPOISON;
407+
}
408+
409+
#else
410+
411+
static inline swp_entry_t make_hwpoison_entry(struct page *page)
412+
{
413+
return swp_entry(0, 0);
414+
}
415+
416+
static inline int is_hwpoison_entry(swp_entry_t swp)
417+
{
418+
return 0;
419+
}
420+
#endif
421+
393422
typedef unsigned long pte_marker;
394423

395424
#define PTE_MARKER_UFFD_WP BIT(0)
@@ -470,16 +499,17 @@ static inline struct page *pfn_swap_entry_to_page(swp_entry_t entry)
470499

471500
/*
472501
* A pfn swap entry is a special type of swap entry that always has a pfn stored
473-
* in the swap offset. They are used to represent unaddressable device memory
474-
* and to restrict access to a page undergoing migration.
502+
* in the swap offset. They can either be used to represent unaddressable device
503+
* memory, to restrict access to a page undergoing migration or to represent a
504+
* pfn which has been hwpoisoned and unmapped.
475505
*/
476506
static inline bool is_pfn_swap_entry(swp_entry_t entry)
477507
{
478508
/* Make sure the swp offset can always store the needed fields */
479509
BUILD_BUG_ON(SWP_TYPE_SHIFT < SWP_PFN_BITS);
480510

481511
return is_migration_entry(entry) || is_device_private_entry(entry) ||
482-
is_device_exclusive_entry(entry);
512+
is_device_exclusive_entry(entry) || is_hwpoison_entry(entry);
483513
}
484514

485515
struct page_vma_mapped_walk;
@@ -548,35 +578,6 @@ static inline int is_pmd_migration_entry(pmd_t pmd)
548578
}
549579
#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
550580

551-
#ifdef CONFIG_MEMORY_FAILURE
552-
553-
/*
554-
* Support for hardware poisoned pages
555-
*/
556-
static inline swp_entry_t make_hwpoison_entry(struct page *page)
557-
{
558-
BUG_ON(!PageLocked(page));
559-
return swp_entry(SWP_HWPOISON, page_to_pfn(page));
560-
}
561-
562-
static inline int is_hwpoison_entry(swp_entry_t entry)
563-
{
564-
return swp_type(entry) == SWP_HWPOISON;
565-
}
566-
567-
#else
568-
569-
static inline swp_entry_t make_hwpoison_entry(struct page *page)
570-
{
571-
return swp_entry(0, 0);
572-
}
573-
574-
static inline int is_hwpoison_entry(swp_entry_t swp)
575-
{
576-
return 0;
577-
}
578-
#endif
579-
580581
static inline int non_swap_entry(swp_entry_t entry)
581582
{
582583
return swp_type(entry) >= MAX_SWAPFILES;

0 commit comments

Comments
 (0)