mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
mm,swapops: update check in is_pfn_swap_entry for hwpoison entries
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 'commit0d206b5d2e("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/20240407130537.16977-1-osalvador@suse.de Fixes:0d206b5d2e("mm/swap: add swp_offset_pfn() to fetch PFN from swap entry") Signed-off-by: Oscar Salvador <osalvador@suse.de> Reported-by: Tony Luck <tony.luck@intel.com> Closes: https://lore.kernel.org/all/Zg8kLSl2yAlA3o5D@agluck-desk3/ Tested-by: Tony Luck <tony.luck@intel.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: David Hildenbrand <david@redhat.com> Acked-by: Miaohe Lin <linmiaohe@huawei.com> Cc: <stable@vger.kernel.org> [6.1.x] Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
1983184c22
commit
07a57a338a
@@ -390,6 +390,35 @@ static inline bool is_migration_entry_dirty(swp_entry_t entry)
|
||||
}
|
||||
#endif /* CONFIG_MIGRATION */
|
||||
|
||||
#ifdef CONFIG_MEMORY_FAILURE
|
||||
|
||||
/*
|
||||
* Support for hardware poisoned pages
|
||||
*/
|
||||
static inline swp_entry_t make_hwpoison_entry(struct page *page)
|
||||
{
|
||||
BUG_ON(!PageLocked(page));
|
||||
return swp_entry(SWP_HWPOISON, page_to_pfn(page));
|
||||
}
|
||||
|
||||
static inline int is_hwpoison_entry(swp_entry_t entry)
|
||||
{
|
||||
return swp_type(entry) == SWP_HWPOISON;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline swp_entry_t make_hwpoison_entry(struct page *page)
|
||||
{
|
||||
return swp_entry(0, 0);
|
||||
}
|
||||
|
||||
static inline int is_hwpoison_entry(swp_entry_t swp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef unsigned long pte_marker;
|
||||
|
||||
#define PTE_MARKER_UFFD_WP BIT(0)
|
||||
@@ -483,8 +512,9 @@ static inline struct folio *pfn_swap_entry_folio(swp_entry_t entry)
|
||||
|
||||
/*
|
||||
* A pfn swap entry is a special type of swap entry that always has a pfn stored
|
||||
* in the swap offset. They are used to represent unaddressable device memory
|
||||
* and to restrict access to a page undergoing migration.
|
||||
* in the swap offset. They can either be used to represent unaddressable device
|
||||
* memory, to restrict access to a page undergoing migration or to represent a
|
||||
* pfn which has been hwpoisoned and unmapped.
|
||||
*/
|
||||
static inline bool is_pfn_swap_entry(swp_entry_t entry)
|
||||
{
|
||||
@@ -492,7 +522,7 @@ static inline bool is_pfn_swap_entry(swp_entry_t entry)
|
||||
BUILD_BUG_ON(SWP_TYPE_SHIFT < SWP_PFN_BITS);
|
||||
|
||||
return is_migration_entry(entry) || is_device_private_entry(entry) ||
|
||||
is_device_exclusive_entry(entry);
|
||||
is_device_exclusive_entry(entry) || is_hwpoison_entry(entry);
|
||||
}
|
||||
|
||||
struct page_vma_mapped_walk;
|
||||
@@ -561,35 +591,6 @@ static inline int is_pmd_migration_entry(pmd_t pmd)
|
||||
}
|
||||
#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
|
||||
|
||||
#ifdef CONFIG_MEMORY_FAILURE
|
||||
|
||||
/*
|
||||
* Support for hardware poisoned pages
|
||||
*/
|
||||
static inline swp_entry_t make_hwpoison_entry(struct page *page)
|
||||
{
|
||||
BUG_ON(!PageLocked(page));
|
||||
return swp_entry(SWP_HWPOISON, page_to_pfn(page));
|
||||
}
|
||||
|
||||
static inline int is_hwpoison_entry(swp_entry_t entry)
|
||||
{
|
||||
return swp_type(entry) == SWP_HWPOISON;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline swp_entry_t make_hwpoison_entry(struct page *page)
|
||||
{
|
||||
return swp_entry(0, 0);
|
||||
}
|
||||
|
||||
static inline int is_hwpoison_entry(swp_entry_t swp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int non_swap_entry(swp_entry_t entry)
|
||||
{
|
||||
return swp_type(entry) >= MAX_SWAPFILES;
|
||||
|
||||
Reference in New Issue
Block a user