/* * 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 multi-bit ECC memory or cache * failure. * * In addition there is a "soft offline" entry point that allows stop using * not-yet-corrupted-by-suspicious pages without killing anything. * * Handles page cache pages in various states. The tricky part * here is that we can access any page asynchronously in respect to * other VM users, because memory failures could happen anytime and * anywhere. This could violate 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. * * There are several operations here with exponential complexity because * of unsuitable VM data structures. For example 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. But since memory corruptions * are rare we hope to get away with this. This avoids impacting the core * VM. *//* * 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"intsysctl_memory_failure_early_kill__read_mostly=0;intsysctl_memory_failure_recovery__read_mostly=1;atomic_long_tmce_bad_pages__read_mostly=ATOMIC_LONG_INIT(0);#if defined(CONFIG_HWPOISON_INJECT) || defined(CONFIG_HWPOISON_INJECT_MODULE)u32hwpoison_filter_enable=0;u32hwpoison_filter_dev_major=~0U;u32hwpoison_filter_dev_minor=~0U;u64hwpoison_filter_flags_mask;u64hwpoison_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);staticinthwpoison_filter_dev(structpage*p){structaddress_space*mapping;dev_tdev;if(hwpoison_filter_dev_major==~0U&&hwpoison_filter_dev_minor==~0U)return0;/* * page_mapping() does not accept slab pages. */if(PageSlab(p