2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-03-31 05:57:33 +04:00
/* Inject a hwpoison memory failure on a arbitrary pfn */
2009-09-16 13:50:17 +04:00
# include <linux/module.h>
# include <linux/debugfs.h>
# include <linux/kernel.h>
# include <linux/mm.h>
2009-12-16 14:19:59 +03:00
# include <linux/swap.h>
# include <linux/pagemap.h>
2010-05-28 04:29:22 +04:00
# include <linux/hugetlb.h>
2009-12-16 14:19:59 +03:00
# include "internal.h"
2009-09-16 13:50:17 +04:00
2009-12-16 14:19:58 +03:00
static struct dentry * hwpoison_dir ;
2009-09-16 13:50:17 +04:00
static int hwpoison_inject ( void * data , u64 val )
{
2009-12-16 14:19:59 +03:00
unsigned long pfn = val ;
struct page * p ;
2024-04-12 22:35:02 +03:00
struct folio * folio ;
2009-12-16 14:19:59 +03:00
int err ;
2009-09-16 13:50:17 +04:00
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
2009-12-16 14:19:59 +03:00
if ( ! pfn_valid ( pfn ) )
return - ENXIO ;
p = pfn_to_page ( pfn ) ;
2024-04-12 22:35:02 +03:00
folio = page_folio ( p ) ;
2009-12-16 14:19:59 +03:00
2013-10-01 00:45:24 +04:00
if ( ! hwpoison_filter_enable )
goto inject ;
2024-04-12 22:35:02 +03:00
shake_folio ( folio ) ;
2009-12-16 14:19:59 +03:00
/*
2022-03-23 00:44:35 +03:00
* This implies unable to support non - LRU pages except free page .
2009-12-16 14:19:59 +03:00
*/
2024-04-12 22:35:02 +03:00
if ( ! folio_test_lru ( folio ) & & ! folio_test_hugetlb ( folio ) & &
! is_free_buddy_page ( p ) )
2020-10-16 06:06:46 +03:00
return 0 ;
2009-12-16 14:19:59 +03:00
/*
2020-10-16 06:06:46 +03:00
* do a racy check to make sure PG_hwpoison will only be set for
* the targeted owner ( or on a free page ) .
2011-12-15 22:48:12 +04:00
* memory_failure ( ) will redo the check reliably inside page lock .
2009-12-16 14:19:59 +03:00
*/
2024-04-12 22:35:02 +03:00
err = hwpoison_filter ( & folio - > page ) ;
2009-12-16 14:19:59 +03:00
if ( err )
2020-10-16 06:06:46 +03:00
return 0 ;
2009-12-16 14:19:59 +03:00
2009-12-16 14:20:01 +03:00
inject :
2014-01-22 03:50:56 +04:00
pr_info ( " Injecting memory failure at pfn %#lx \n " , pfn ) ;
2022-06-15 12:32:09 +03:00
err = memory_failure ( pfn , MF_SW_SIMULATED ) ;
2022-03-23 00:44:38 +03:00
return ( err = = - EOPNOTSUPP ) ? 0 : err ;
2009-09-16 13:50:17 +04:00
}
2009-12-16 14:19:58 +03:00
static int hwpoison_unpoison ( void * data , u64 val )
{
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
return unpoison_memory ( val ) ;
}
2019-12-01 04:57:35 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( hwpoison_fops , NULL , hwpoison_inject , " %lli \n " ) ;
DEFINE_DEBUGFS_ATTRIBUTE ( unpoison_fops , NULL , hwpoison_unpoison , " %lli \n " ) ;
2009-09-16 13:50:17 +04:00
2022-09-06 12:35:30 +03:00
static void __exit pfn_inject_exit ( void )
2009-09-16 13:50:17 +04:00
{
2022-05-13 06:23:10 +03:00
hwpoison_filter_enable = 0 ;
2014-08-07 03:06:41 +04:00
debugfs_remove_recursive ( hwpoison_dir ) ;
2009-09-16 13:50:17 +04:00
}
2022-09-06 12:35:30 +03:00
static int __init pfn_inject_init ( void )
2009-09-16 13:50:17 +04:00
{
hwpoison_dir = debugfs_create_dir ( " hwpoison " , NULL ) ;
2009-12-16 14:19:58 +03:00
/*
* Note that the below poison / unpoison interfaces do not involve
* hardware status change , hence do not require hardware support .
* They are mainly for testing hwpoison in software level .
*/
2019-01-22 18:21:10 +03:00
debugfs_create_file ( " corrupt-pfn " , 0200 , hwpoison_dir , NULL ,
& hwpoison_fops ) ;
debugfs_create_file ( " unpoison-pfn " , 0200 , hwpoison_dir , NULL ,
& unpoison_fops ) ;
debugfs_create_u32 ( " corrupt-filter-enable " , 0600 , hwpoison_dir ,
& hwpoison_filter_enable ) ;
debugfs_create_u32 ( " corrupt-filter-dev-major " , 0600 , hwpoison_dir ,
& hwpoison_filter_dev_major ) ;
debugfs_create_u32 ( " corrupt-filter-dev-minor " , 0600 , hwpoison_dir ,
& hwpoison_filter_dev_minor ) ;
debugfs_create_u64 ( " corrupt-filter-flags-mask " , 0600 , hwpoison_dir ,
& hwpoison_filter_flags_mask ) ;
debugfs_create_u64 ( " corrupt-filter-flags-value " , 0600 , hwpoison_dir ,
& hwpoison_filter_flags_value ) ;
2009-12-16 14:19:59 +03:00
2015-09-10 01:35:31 +03:00
# ifdef CONFIG_MEMCG
2019-01-22 18:21:10 +03:00
debugfs_create_u64 ( " corrupt-filter-memcg " , 0600 , hwpoison_dir ,
& hwpoison_filter_memcg ) ;
2009-12-16 14:19:59 +03:00
# endif
2009-09-16 13:50:17 +04:00
return 0 ;
}
module_init ( pfn_inject_init ) ;
module_exit ( pfn_inject_exit ) ;
2024-05-13 22:37:38 +03:00
MODULE_DESCRIPTION ( " HWPoison pages injector " ) ;
2009-09-16 13:50:17 +04:00
MODULE_LICENSE ( " GPL " ) ;