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 989429cfed88..c4c8f2e1dd15 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -341,6 +341,64 @@ static inline int memory_probe_init(void) | |||
341 | } | 341 | } |
342 | #endif | 342 | #endif |
343 | 343 | ||
344 | #ifdef CONFIG_MEMORY_FAILURE | ||
345 | /* | ||
346 | * Support for offlining pages of memory | ||
347 | */ | ||
348 | |||
349 | /* Soft offline a page */ | ||
350 | static ssize_t | ||
351 | store_soft_offline_page(struct class *class, const char *buf, size_t count) | ||
352 | { | ||
353 | int ret; | ||
354 | u64 pfn; | ||
355 | if (!capable(CAP_SYS_ADMIN)) | ||
356 | return -EPERM; | ||
357 | if (strict_strtoull(buf, 0, &pfn) < 0) | ||
358 | return -EINVAL; | ||
359 | pfn >>= PAGE_SHIFT; | ||
360 | if (!pfn_valid(pfn)) | ||
361 | return -ENXIO; | ||
362 | ret = soft_offline_page(pfn_to_page(pfn), 0); | ||
363 | return ret == 0 ? count : ret; | ||
364 | } | ||
365 | |||
366 | /* Forcibly offline a page, including killing processes. */ | ||
367 | static ssize_t | ||
368 | store_hard_offline_page(struct class *class, const char *buf, size_t count) | ||
369 | { | ||
370 | int ret; | ||
371 | u64 pfn; | ||
372 | if (!capable(CAP_SYS_ADMIN)) | ||
373 | return -EPERM; | ||
374 | if (strict_strtoull(buf, 0, &pfn) < 0) | ||
375 | return -EINVAL; | ||
376 | pfn >>= PAGE_SHIFT; | ||
377 | ret = __memory_failure(pfn, 0, 0); | ||
378 | return ret ? ret : count; | ||
379 | } | ||
380 | |||
381 | static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); | ||
382 | static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); | ||
383 | |||
384 | static __init int memory_fail_init(void) | ||
385 | { | ||
386 | int err; | ||
387 | |||
388 | err = sysfs_create_file(&memory_sysdev_class.kset.kobj, | ||
389 | &class_attr_soft_offline_page.attr); | ||
390 | if (!err) | ||
391 | err = sysfs_create_file(&memory_sysdev_class.kset.kobj, | ||
392 | &class_attr_hard_offline_page.attr); | ||
393 | return err; | ||
394 | } | ||
395 | #else | ||
396 | static inline int memory_fail_init(void) | ||
397 | { | ||
398 | return 0; | ||
399 | } | ||
400 | #endif | ||
401 | |||
344 | /* | 402 | /* |
345 | * Note that phys_device is optional. It is here to allow for | 403 | * Note that phys_device is optional. It is here to allow for |
346 | * differentiation between which *physical* devices each | 404 | * differentiation between which *physical* devices each |
@@ -473,6 +531,9 @@ int __init memory_dev_init(void) | |||
473 | err = memory_probe_init(); | 531 | err = memory_probe_init(); |
474 | if (!ret) | 532 | if (!ret) |
475 | ret = err; | 533 | ret = err; |
534 | err = memory_fail_init(); | ||
535 | if (!ret) | ||
536 | ret = err; | ||
476 | err = block_size_init(); | 537 | err = block_size_init(); |
477 | if (!ret) | 538 | if (!ret) |
478 | ret = err; | 539 | ret = err; |