Commit cd42f4a3 authored by Tony Luck's avatar Tony Luck

HWPOISON: Clean up memory_failure() vs. __memory_failure()

There is only one caller of memory_failure(), all other users call
__memory_failure() and pass in the flags argument explicitly. The
lone user of memory_failure() will soon need to pass flags too.

Add flags argument to the callsite in mce.c. Delete the old memory_failure()
function, and then rename __memory_failure() without the leading "__".

Provide clearer message when action optional memory errors are ignored.
Acked-by: default avatarBorislav Petkov <bp@amd64.org>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent dc47ce90
...@@ -1046,11 +1046,15 @@ void do_machine_check(struct pt_regs *regs, long error_code) ...@@ -1046,11 +1046,15 @@ void do_machine_check(struct pt_regs *regs, long error_code)
} }
EXPORT_SYMBOL_GPL(do_machine_check); EXPORT_SYMBOL_GPL(do_machine_check);
/* dummy to break dependency. actual code is in mm/memory-failure.c */ #ifndef CONFIG_MEMORY_FAILURE
void __attribute__((weak)) memory_failure(unsigned long pfn, int vector) int memory_failure(unsigned long pfn, int vector, int flags)
{ {
printk(KERN_ERR "Action optional memory failure at %lx ignored\n", pfn); printk(KERN_ERR "Uncorrected memory error in page 0x%lx ignored\n"
"Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n", pfn);
return 0;
} }
#endif
/* /*
* Called after mce notification in process context. This code * Called after mce notification in process context. This code
...@@ -1068,7 +1072,7 @@ void mce_notify_process(void) ...@@ -1068,7 +1072,7 @@ void mce_notify_process(void)
unsigned long pfn; unsigned long pfn;
mce_notify_irq(); mce_notify_irq();
while (mce_ring_get(&pfn)) while (mce_ring_get(&pfn))
memory_failure(pfn, MCE_VECTOR); memory_failure(pfn, MCE_VECTOR, 0);
} }
static void mce_process_work(struct work_struct *dummy) static void mce_process_work(struct work_struct *dummy)
......
...@@ -474,7 +474,7 @@ store_hard_offline_page(struct class *class, ...@@ -474,7 +474,7 @@ store_hard_offline_page(struct class *class,
if (strict_strtoull(buf, 0, &pfn) < 0) if (strict_strtoull(buf, 0, &pfn) < 0)
return -EINVAL; return -EINVAL;
pfn >>= PAGE_SHIFT; pfn >>= PAGE_SHIFT;
ret = __memory_failure(pfn, 0, 0); ret = memory_failure(pfn, 0, 0);
return ret ? ret : count; return ret ? ret : count;
} }
......
...@@ -1607,8 +1607,7 @@ void vmemmap_populate_print_last(void); ...@@ -1607,8 +1607,7 @@ void vmemmap_populate_print_last(void);
enum mf_flags { enum mf_flags {
MF_COUNT_INCREASED = 1 << 0, MF_COUNT_INCREASED = 1 << 0,
}; };
extern void memory_failure(unsigned long pfn, int trapno); extern int memory_failure(unsigned long pfn, int trapno, int flags);
extern int __memory_failure(unsigned long pfn, int trapno, int flags);
extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
extern int unpoison_memory(unsigned long pfn); extern int unpoison_memory(unsigned long pfn);
extern int sysctl_memory_failure_early_kill; extern int sysctl_memory_failure_early_kill;
......
...@@ -45,7 +45,7 @@ static int hwpoison_inject(void *data, u64 val) ...@@ -45,7 +45,7 @@ static int hwpoison_inject(void *data, u64 val)
* do a racy check with elevated page count, to make sure PG_hwpoison * do a racy check with elevated page count, to make sure PG_hwpoison
* will only be set for the targeted owner (or on a free page). * will only be set for the targeted owner (or on a free page).
* We temporarily take page lock for try_get_mem_cgroup_from_page(). * We temporarily take page lock for try_get_mem_cgroup_from_page().
* __memory_failure() will redo the check reliably inside page lock. * memory_failure() will redo the check reliably inside page lock.
*/ */
lock_page(hpage); lock_page(hpage);
err = hwpoison_filter(hpage); err = hwpoison_filter(hpage);
...@@ -55,7 +55,7 @@ static int hwpoison_inject(void *data, u64 val) ...@@ -55,7 +55,7 @@ static int hwpoison_inject(void *data, u64 val)
inject: inject:
printk(KERN_INFO "Injecting memory failure at pfn %lx\n", pfn); printk(KERN_INFO "Injecting memory failure at pfn %lx\n", pfn);
return __memory_failure(pfn, 18, MF_COUNT_INCREASED); return memory_failure(pfn, 18, MF_COUNT_INCREASED);
} }
static int hwpoison_unpoison(void *data, u64 val) static int hwpoison_unpoison(void *data, u64 val)
......
...@@ -251,7 +251,7 @@ static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end) ...@@ -251,7 +251,7 @@ static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
printk(KERN_INFO "Injecting memory failure for page %lx at %lx\n", printk(KERN_INFO "Injecting memory failure for page %lx at %lx\n",
page_to_pfn(p), start); page_to_pfn(p), start);
/* Ignore return value for now */ /* Ignore return value for now */
__memory_failure(page_to_pfn(p), 0, MF_COUNT_INCREASED); memory_failure(page_to_pfn(p), 0, MF_COUNT_INCREASED);
} }
return ret; return ret;
} }
......
...@@ -984,7 +984,25 @@ static void clear_page_hwpoison_huge_page(struct page *hpage) ...@@ -984,7 +984,25 @@ static void clear_page_hwpoison_huge_page(struct page *hpage)
ClearPageHWPoison(hpage + i); ClearPageHWPoison(hpage + i);
} }
int __memory_failure(unsigned long pfn, int trapno, int flags) /**
* memory_failure - Handle memory failure of a page.
* @pfn: Page Number of the corrupted page
* @trapno: Trap number reported in the signal to user space.
* @flags: fine tune action taken
*
* This function is called by the low level machine check code
* of an architecture when it detects hardware memory corruption
* of a page. It tries its best to recover, which includes
* dropping pages, killing processes etc.
*
* The function is primarily of use for corruptions that
* happen outside the current execution context (e.g. when
* detected by a background scrubber)
*
* Must run in process context (e.g. a work queue) with interrupts
* enabled and no spinlocks hold.
*/
int memory_failure(unsigned long pfn, int trapno, int flags)
{ {
struct page_state *ps; struct page_state *ps;
struct page *p; struct page *p;
...@@ -1156,29 +1174,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) ...@@ -1156,29 +1174,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
unlock_page(hpage); unlock_page(hpage);
return res; return res;
} }
EXPORT_SYMBOL_GPL(__memory_failure); EXPORT_SYMBOL_GPL(memory_failure);
/**
* memory_failure - Handle memory failure of a page.
* @pfn: Page Number of the corrupted page
* @trapno: Trap number reported in the signal to user space.
*
* This function is called by the low level machine check code
* of an architecture when it detects hardware memory corruption
* of a page. It tries its best to recover, which includes
* dropping pages, killing processes etc.
*
* The function is primarily of use for corruptions that
* happen outside the current execution context (e.g. when
* detected by a background scrubber)
*
* Must run in process context (e.g. a work queue) with interrupts
* enabled and no spinlocks hold.
*/
void memory_failure(unsigned long pfn, int trapno)
{
__memory_failure(pfn, trapno, 0);
}
#define MEMORY_FAILURE_FIFO_ORDER 4 #define MEMORY_FAILURE_FIFO_ORDER 4
#define MEMORY_FAILURE_FIFO_SIZE (1 << MEMORY_FAILURE_FIFO_ORDER) #define MEMORY_FAILURE_FIFO_SIZE (1 << MEMORY_FAILURE_FIFO_ORDER)
...@@ -1251,7 +1247,7 @@ static void memory_failure_work_func(struct work_struct *work) ...@@ -1251,7 +1247,7 @@ static void memory_failure_work_func(struct work_struct *work)
spin_unlock_irqrestore(&mf_cpu->lock, proc_flags); spin_unlock_irqrestore(&mf_cpu->lock, proc_flags);
if (!gotten) if (!gotten)
break; break;
__memory_failure(entry.pfn, entry.trapno, entry.flags); memory_failure(entry.pfn, entry.trapno, entry.flags);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment