page-types: add hwpoison/unpoison feature
For hwpoison stress testing. The debugfs mount point is assumed to be /debug/. Signed-off-by: Wu Fengguang <fengguang.wu@intel.com> Cc: Andi Kleen <andi@firstfloor.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
					parent
					
						
							
								48640d69f5
							
						
					
				
			
			
				commit
				
					
						a54fed9f70
					
				
			
		
					 1 changed files with 72 additions and 1 deletions
				
			
		| 
						 | 
					@ -170,6 +170,13 @@ static int		page_size;
 | 
				
			||||||
static int		pagemap_fd;
 | 
					static int		pagemap_fd;
 | 
				
			||||||
static int		kpageflags_fd;
 | 
					static int		kpageflags_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int		opt_hwpoison;
 | 
				
			||||||
 | 
					static int		opt_unpoison;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char		*hwpoison_debug_fs = "/debug/hwpoison";
 | 
				
			||||||
 | 
					static int		hwpoison_inject_fd;
 | 
				
			||||||
 | 
					static int		hwpoison_forget_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define HASH_SHIFT	13
 | 
					#define HASH_SHIFT	13
 | 
				
			||||||
#define HASH_SIZE	(1 << HASH_SHIFT)
 | 
					#define HASH_SIZE	(1 << HASH_SHIFT)
 | 
				
			||||||
#define HASH_MASK	(HASH_SIZE - 1)
 | 
					#define HASH_MASK	(HASH_SIZE - 1)
 | 
				
			||||||
| 
						 | 
					@ -446,6 +453,53 @@ static uint64_t kpageflags_flags(uint64_t flags)
 | 
				
			||||||
	return flags;
 | 
						return flags;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * page actions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void prepare_hwpoison_fd(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[100];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opt_hwpoison && !hwpoison_inject_fd) {
 | 
				
			||||||
 | 
							sprintf(buf, "%s/corrupt-pfn", hwpoison_debug_fs);
 | 
				
			||||||
 | 
							hwpoison_inject_fd = checked_open(buf, O_WRONLY);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opt_unpoison && !hwpoison_forget_fd) {
 | 
				
			||||||
 | 
							sprintf(buf, "%s/renew-pfn", hwpoison_debug_fs);
 | 
				
			||||||
 | 
							hwpoison_forget_fd = checked_open(buf, O_WRONLY);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int hwpoison_page(unsigned long offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[100];
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = sprintf(buf, "0x%lx\n", offset);
 | 
				
			||||||
 | 
						len = write(hwpoison_inject_fd, buf, len);
 | 
				
			||||||
 | 
						if (len < 0) {
 | 
				
			||||||
 | 
							perror("hwpoison inject");
 | 
				
			||||||
 | 
							return len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int unpoison_page(unsigned long offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[100];
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = sprintf(buf, "0x%lx\n", offset);
 | 
				
			||||||
 | 
						len = write(hwpoison_forget_fd, buf, len);
 | 
				
			||||||
 | 
						if (len < 0) {
 | 
				
			||||||
 | 
							perror("hwpoison forget");
 | 
				
			||||||
 | 
							return len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * page frame walker
 | 
					 * page frame walker
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -485,6 +539,11 @@ static void add_page(unsigned long voffset,
 | 
				
			||||||
	if (!bit_mask_ok(flags))
 | 
						if (!bit_mask_ok(flags))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opt_hwpoison)
 | 
				
			||||||
 | 
							hwpoison_page(offset);
 | 
				
			||||||
 | 
						if (opt_unpoison)
 | 
				
			||||||
 | 
							unpoison_page(offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (opt_list == 1)
 | 
						if (opt_list == 1)
 | 
				
			||||||
		show_page_range(voffset, offset, flags);
 | 
							show_page_range(voffset, offset, flags);
 | 
				
			||||||
	else if (opt_list == 2)
 | 
						else if (opt_list == 2)
 | 
				
			||||||
| 
						 | 
					@ -624,6 +683,8 @@ static void usage(void)
 | 
				
			||||||
"            -l|--list                 Show page details in ranges\n"
 | 
					"            -l|--list                 Show page details in ranges\n"
 | 
				
			||||||
"            -L|--list-each            Show page details one by one\n"
 | 
					"            -L|--list-each            Show page details one by one\n"
 | 
				
			||||||
"            -N|--no-summary           Don't show summay info\n"
 | 
					"            -N|--no-summary           Don't show summay info\n"
 | 
				
			||||||
 | 
					"            -X|--hwpoison             hwpoison pages\n"
 | 
				
			||||||
 | 
					"            -x|--unpoison             unpoison pages\n"
 | 
				
			||||||
"            -h|--help                 Show this usage message\n"
 | 
					"            -h|--help                 Show this usage message\n"
 | 
				
			||||||
"addr-spec:\n"
 | 
					"addr-spec:\n"
 | 
				
			||||||
"            N                         one page at offset N (unit: pages)\n"
 | 
					"            N                         one page at offset N (unit: pages)\n"
 | 
				
			||||||
| 
						 | 
					@ -833,6 +894,8 @@ static struct option opts[] = {
 | 
				
			||||||
	{ "list"      , 0, NULL, 'l' },
 | 
						{ "list"      , 0, NULL, 'l' },
 | 
				
			||||||
	{ "list-each" , 0, NULL, 'L' },
 | 
						{ "list-each" , 0, NULL, 'L' },
 | 
				
			||||||
	{ "no-summary", 0, NULL, 'N' },
 | 
						{ "no-summary", 0, NULL, 'N' },
 | 
				
			||||||
 | 
						{ "hwpoison"  , 0, NULL, 'X' },
 | 
				
			||||||
 | 
						{ "unpoison"  , 0, NULL, 'x' },
 | 
				
			||||||
	{ "help"      , 0, NULL, 'h' },
 | 
						{ "help"      , 0, NULL, 'h' },
 | 
				
			||||||
	{ NULL        , 0, NULL, 0 }
 | 
						{ NULL        , 0, NULL, 0 }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -844,7 +907,7 @@ int main(int argc, char *argv[])
 | 
				
			||||||
	page_size = getpagesize();
 | 
						page_size = getpagesize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((c = getopt_long(argc, argv,
 | 
						while ((c = getopt_long(argc, argv,
 | 
				
			||||||
				"rp:f:a:b:lLNh", opts, NULL)) != -1) {
 | 
									"rp:f:a:b:lLNXxh", opts, NULL)) != -1) {
 | 
				
			||||||
		switch (c) {
 | 
							switch (c) {
 | 
				
			||||||
		case 'r':
 | 
							case 'r':
 | 
				
			||||||
			opt_raw = 1;
 | 
								opt_raw = 1;
 | 
				
			||||||
| 
						 | 
					@ -870,6 +933,14 @@ int main(int argc, char *argv[])
 | 
				
			||||||
		case 'N':
 | 
							case 'N':
 | 
				
			||||||
			opt_no_summary = 1;
 | 
								opt_no_summary = 1;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 'X':
 | 
				
			||||||
 | 
								opt_hwpoison = 1;
 | 
				
			||||||
 | 
								prepare_hwpoison_fd();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'x':
 | 
				
			||||||
 | 
								opt_unpoison = 1;
 | 
				
			||||||
 | 
								prepare_hwpoison_fd();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case 'h':
 | 
							case 'h':
 | 
				
			||||||
			usage();
 | 
								usage();
 | 
				
			||||||
			exit(0);
 | 
								exit(0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue