diff options
Diffstat (limited to 'drivers/base/memory.c')
| -rw-r--r-- | drivers/base/memory.c | 61 | 
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 989429cfed8..c4c8f2e1dd1 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -341,6 +341,64 @@ static inline int memory_probe_init(void)  }  #endif +#ifdef CONFIG_MEMORY_FAILURE +/* + * Support for offlining pages of memory + */ + +/* Soft offline a page */ +static ssize_t +store_soft_offline_page(struct class *class, const char *buf, size_t count) +{ +	int ret; +	u64 pfn; +	if (!capable(CAP_SYS_ADMIN)) +		return -EPERM; +	if (strict_strtoull(buf, 0, &pfn) < 0) +		return -EINVAL; +	pfn >>= PAGE_SHIFT; +	if (!pfn_valid(pfn)) +		return -ENXIO; +	ret = soft_offline_page(pfn_to_page(pfn), 0); +	return ret == 0 ? count : ret; +} + +/* Forcibly offline a page, including killing processes. */ +static ssize_t +store_hard_offline_page(struct class *class, const char *buf, size_t count) +{ +	int ret; +	u64 pfn; +	if (!capable(CAP_SYS_ADMIN)) +		return -EPERM; +	if (strict_strtoull(buf, 0, &pfn) < 0) +		return -EINVAL; +	pfn >>= PAGE_SHIFT; +	ret = __memory_failure(pfn, 0, 0); +	return ret ? ret : count; +} + +static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); +static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); + +static __init int memory_fail_init(void) +{ +	int err; + +	err = sysfs_create_file(&memory_sysdev_class.kset.kobj, +				&class_attr_soft_offline_page.attr); +	if (!err) +		err = sysfs_create_file(&memory_sysdev_class.kset.kobj, +				&class_attr_hard_offline_page.attr); +	return err; +} +#else +static inline int memory_fail_init(void) +{ +	return 0; +} +#endif +  /*   * Note that phys_device is optional.  It is here to allow for   * differentiation between which *physical* devices each @@ -473,6 +531,9 @@ int __init memory_dev_init(void)  	err = memory_probe_init();  	if (!ret)  		ret = err; +	err = memory_fail_init(); +	if (!ret) +		ret = err;  	err = block_size_init();  	if (!ret)  		ret = err;  |