aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/memory.c')
-rw-r--r--drivers/base/memory.c112
1 files changed, 102 insertions, 10 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 989429cfed88..933442f40321 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -22,6 +22,7 @@
22#include <linux/mm.h> 22#include <linux/mm.h>
23#include <linux/mutex.h> 23#include <linux/mutex.h>
24#include <linux/stat.h> 24#include <linux/stat.h>
25#include <linux/slab.h>
25 26
26#include <asm/atomic.h> 27#include <asm/atomic.h>
27#include <asm/uaccess.h> 28#include <asm/uaccess.h>
@@ -44,7 +45,7 @@ static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uev
44 return retval; 45 return retval;
45} 46}
46 47
47static struct kset_uevent_ops memory_uevent_ops = { 48static const struct kset_uevent_ops memory_uevent_ops = {
48 .name = memory_uevent_name, 49 .name = memory_uevent_name,
49 .uevent = memory_uevent, 50 .uevent = memory_uevent,
50}; 51};
@@ -63,6 +64,20 @@ void unregister_memory_notifier(struct notifier_block *nb)
63} 64}
64EXPORT_SYMBOL(unregister_memory_notifier); 65EXPORT_SYMBOL(unregister_memory_notifier);
65 66
67static ATOMIC_NOTIFIER_HEAD(memory_isolate_chain);
68
69int register_memory_isolate_notifier(struct notifier_block *nb)
70{
71 return atomic_notifier_chain_register(&memory_isolate_chain, nb);
72}
73EXPORT_SYMBOL(register_memory_isolate_notifier);
74
75void unregister_memory_isolate_notifier(struct notifier_block *nb)
76{
77 atomic_notifier_chain_unregister(&memory_isolate_chain, nb);
78}
79EXPORT_SYMBOL(unregister_memory_isolate_notifier);
80
66/* 81/*
67 * register_memory - Setup a sysfs device for a memory block 82 * register_memory - Setup a sysfs device for a memory block
68 */ 83 */
@@ -157,6 +172,11 @@ int memory_notify(unsigned long val, void *v)
157 return blocking_notifier_call_chain(&memory_chain, val, v); 172 return blocking_notifier_call_chain(&memory_chain, val, v);
158} 173}
159 174
175int memory_isolate_notify(unsigned long val, void *v)
176{
177 return atomic_notifier_call_chain(&memory_isolate_chain, val, v);
178}
179
160/* 180/*
161 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is 181 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
162 * OK to have direct references to sparsemem variables in here. 182 * OK to have direct references to sparsemem variables in here.
@@ -290,17 +310,18 @@ static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL);
290 * Block size attribute stuff 310 * Block size attribute stuff
291 */ 311 */
292static ssize_t 312static ssize_t
293print_block_size(struct class *class, char *buf) 313print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr,
314 char *buf)
294{ 315{
295 return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE); 316 return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
296} 317}
297 318
298static CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); 319static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
299 320
300static int block_size_init(void) 321static int block_size_init(void)
301{ 322{
302 return sysfs_create_file(&memory_sysdev_class.kset.kobj, 323 return sysfs_create_file(&memory_sysdev_class.kset.kobj,
303 &class_attr_block_size_bytes.attr); 324 &attr_block_size_bytes.attr);
304} 325}
305 326
306/* 327/*
@@ -311,7 +332,8 @@ static int block_size_init(void)
311 */ 332 */
312#ifdef CONFIG_ARCH_MEMORY_PROBE 333#ifdef CONFIG_ARCH_MEMORY_PROBE
313static ssize_t 334static ssize_t
314memory_probe_store(struct class *class, const char *buf, size_t count) 335memory_probe_store(struct class *class, struct class_attribute *attr,
336 const char *buf, size_t count)
315{ 337{
316 u64 phys_addr; 338 u64 phys_addr;
317 int nid; 339 int nid;
@@ -341,17 +363,83 @@ static inline int memory_probe_init(void)
341} 363}
342#endif 364#endif
343 365
366#ifdef CONFIG_MEMORY_FAILURE
367/*
368 * Support for offlining pages of memory
369 */
370
371/* Soft offline a page */
372static ssize_t
373store_soft_offline_page(struct class *class,
374 struct class_attribute *attr,
375 const char *buf, size_t count)
376{
377 int ret;
378 u64 pfn;
379 if (!capable(CAP_SYS_ADMIN))
380 return -EPERM;
381 if (strict_strtoull(buf, 0, &pfn) < 0)
382 return -EINVAL;
383 pfn >>= PAGE_SHIFT;
384 if (!pfn_valid(pfn))
385 return -ENXIO;
386 ret = soft_offline_page(pfn_to_page(pfn), 0);
387 return ret == 0 ? count : ret;
388}
389
390/* Forcibly offline a page, including killing processes. */
391static ssize_t
392store_hard_offline_page(struct class *class,
393 struct class_attribute *attr,
394 const char *buf, size_t count)
395{
396 int ret;
397 u64 pfn;
398 if (!capable(CAP_SYS_ADMIN))
399 return -EPERM;
400 if (strict_strtoull(buf, 0, &pfn) < 0)
401 return -EINVAL;
402 pfn >>= PAGE_SHIFT;
403 ret = __memory_failure(pfn, 0, 0);
404 return ret ? ret : count;
405}
406
407static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
408static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
409
410static __init int memory_fail_init(void)
411{
412 int err;
413
414 err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
415 &class_attr_soft_offline_page.attr);
416 if (!err)
417 err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
418 &class_attr_hard_offline_page.attr);
419 return err;
420}
421#else
422static inline int memory_fail_init(void)
423{
424 return 0;
425}
426#endif
427
344/* 428/*
345 * Note that phys_device is optional. It is here to allow for 429 * Note that phys_device is optional. It is here to allow for
346 * differentiation between which *physical* devices each 430 * differentiation between which *physical* devices each
347 * section belongs to... 431 * section belongs to...
348 */ 432 */
433int __weak arch_get_memory_phys_device(unsigned long start_pfn)
434{
435 return 0;
436}
349 437
350static int add_memory_block(int nid, struct mem_section *section, 438static int add_memory_block(int nid, struct mem_section *section,
351 unsigned long state, int phys_device, 439 unsigned long state, enum mem_add_context context)
352 enum mem_add_context context)
353{ 440{
354 struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); 441 struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL);
442 unsigned long start_pfn;
355 int ret = 0; 443 int ret = 0;
356 444
357 if (!mem) 445 if (!mem)
@@ -360,7 +448,8 @@ static int add_memory_block(int nid, struct mem_section *section,
360 mem->phys_index = __section_nr(section); 448 mem->phys_index = __section_nr(section);
361 mem->state = state; 449 mem->state = state;
362 mutex_init(&mem->state_mutex); 450 mutex_init(&mem->state_mutex);
363 mem->phys_device = phys_device; 451 start_pfn = section_nr_to_pfn(mem->phys_index);
452 mem->phys_device = arch_get_memory_phys_device(start_pfn);
364 453
365 ret = register_memory(mem, section); 454 ret = register_memory(mem, section);
366 if (!ret) 455 if (!ret)
@@ -432,7 +521,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
432 */ 521 */
433int register_new_memory(int nid, struct mem_section *section) 522int register_new_memory(int nid, struct mem_section *section)
434{ 523{
435 return add_memory_block(nid, section, MEM_OFFLINE, 0, HOTPLUG); 524 return add_memory_block(nid, section, MEM_OFFLINE, HOTPLUG);
436} 525}
437 526
438int unregister_memory_section(struct mem_section *section) 527int unregister_memory_section(struct mem_section *section)
@@ -465,7 +554,7 @@ int __init memory_dev_init(void)
465 if (!present_section_nr(i)) 554 if (!present_section_nr(i))
466 continue; 555 continue;
467 err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 556 err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE,
468 0, BOOT); 557 BOOT);
469 if (!ret) 558 if (!ret)
470 ret = err; 559 ret = err;
471 } 560 }
@@ -473,6 +562,9 @@ int __init memory_dev_init(void)
473 err = memory_probe_init(); 562 err = memory_probe_init();
474 if (!ret) 563 if (!ret)
475 ret = err; 564 ret = err;
565 err = memory_fail_init();
566 if (!ret)
567 ret = err;
476 err = block_size_init(); 568 err = block_size_init();
477 if (!ret) 569 if (!ret)
478 ret = err; 570 ret = err;