/* * Copyright (C) 2008, 2009 Intel Corporation * Authors: Andi Kleen, Fengguang Wu * * This software may be redistributed and/or modified under the terms of * the GNU General Public License ("GPL") version 2 only as published by the * Free Software Foundation. * * High level machine check handler. Handles pages reported by the * hardware as being corrupted usually due to a 2bit ECC memory or cache * failure. * * Handles page cache pages in various states. The tricky part * here is that we can access any page asynchronous to other VM * users, because memory failures could happen anytime and anywhere, * possibly violating some of their assumptions. This is why this code * has to be extremely careful. Generally it tries to use normal locking * rules, as in get the standard locks, even if that means the * error handling takes potentially a long time. * * The operation to map back from RMAP chains to processes has to walk * the complete process list and has non linear complexity with the number * mappings. In short it can be quite slow. But since memory corruptions * are rare we hope to get away with this. *//* * Notebook: * - hugetlb needs more code * - kcore/oldmem/vmcore/mem/kmem check for hwpoison pages * - pass bad pages to kdump next kernel */#define DEBUG 1/* remove me in 2.6.34 */#include <linux/kernel.h>#include <linux/mm.h>#include <linux/page-flags.h>#include <linux/kernel-page-flags.h>#include <linux/sched.h>#include <linux/ksm.h>#include <linux/rmap.h>#include <linux/pagemap.h>#include <linux/swap.h>#include <linux/backing-dev.h>#include <linux/migrate.h>#include <linux/page-isolation.h>#include <linux/suspend.h>#include <linux/slab.h>#include <linux/swapops.h>#include <linux/hugetlb.h>#include"internal.h"int sysctl_memory_failure_early_kill __read_mostly =0;int sysctl_memory_failure_recovery __read_mostly =1;
atomic_long_t mce_bad_pages __read_mostly =ATOMIC_LONG_INIT(0);#if defined(CONFIG_HWPOISON_INJECT) || defined(CONFIG_HWPOISON_INJECT_MODULE)
u32 hwpoison_filter_enable =0;
u32 hwpoison_filter_dev_major = ~0U;
u32 hwpoison_filter_dev_minor = ~0U;
u64 hwpoison_filter_flags_mask;
u64 hwpoison_filter_flags_value;EXPORT_SYMBOL_GPL(hwpoison_filter_enable);EXPORT_SYMBOL_GPL(hwpoison_filter_dev_major);EXPORT_SYMBOL_GPL(hwpoison_filter_dev_minor);EXPORT_SYMBOL_GPL(hwpoison_filter_flags_mask);EXPORT_SYMBOL_GPL(hwpoison_filter_flags_value);static inthwpoison_filter_dev(struct page *p){struct address_space *mapping;
dev_t dev;if(hwpoison_filter_dev_major == ~0U&&
hwpoison_filter_dev_minor == ~0U)return0;/* * page_mapping() does not accept slab page */if(PageSlab(p))return-EINVAL;
mapping =page_mapping(p);if(mapping == NULL || mapping->host == NULL)return-EINVAL;
dev = mapping->host->i_sb->s_dev;if(hwpoison_filter_dev_major != ~0U&&
hwpoison_filter_dev_major !=MAJOR