Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memory-hotplug: add sysfs valid_zones attribute

Currently memory-hotplug has two limits:

1. If the memory block is in ZONE_NORMAL, you can change it to
ZONE_MOVABLE, but this memory block must be adjacent to ZONE_MOVABLE.

2. If the memory block is in ZONE_MOVABLE, you can change it to
ZONE_NORMAL, but this memory block must be adjacent to ZONE_NORMAL.

With this patch, we can easy to know a memory block can be onlined to
which zone, and don't need to know the above two limits.

Updated the related Documentation.

[akpm@linux-foundation.org: use conventional comment layout]
[akpm@linux-foundation.org: fix build with CONFIG_MEMORY_HOTREMOVE=n]
[akpm@linux-foundation.org: remove unused local zone_prev]
Signed-off-by: Zhang Zhen <zhenzhang.zhang@huawei.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Toshi Kani <toshi.kani@hp.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Zhang Zhen and committed by
Linus Torvalds
ed2f2400 cc71aba3

+62 -2
+8
Documentation/ABI/testing/sysfs-devices-memory
··· 61 61 http://www.ibm.com/developerworks/wikis/display/LinuxP/powerpc-utils 62 62 63 63 64 + What: /sys/devices/system/memory/memoryX/valid_zones 65 + Date: July 2014 66 + Contact: Zhang Zhen <zhenzhang.zhang@huawei.com> 67 + Description: 68 + The file /sys/devices/system/memory/memoryX/valid_zones is 69 + read-only and is designed to show which zone this memory 70 + block can be onlined to. 71 + 64 72 What: /sys/devices/system/memoryX/nodeY 65 73 Date: October 2009 66 74 Contact: Linux Memory Management list <linux-mm@kvack.org>
+10 -1
Documentation/memory-hotplug.txt
··· 155 155 /sys/devices/system/memory/memoryXXX/phys_device 156 156 /sys/devices/system/memory/memoryXXX/state 157 157 /sys/devices/system/memory/memoryXXX/removable 158 + /sys/devices/system/memory/memoryXXX/valid_zones 158 159 159 160 'phys_index' : read-only and contains memory block id, same as XXX. 160 161 'state' : read-write ··· 171 170 block is removable and a value of 0 indicates that 172 171 it is not removable. A memory block is removable only if 173 172 every section in the block is removable. 173 + 'valid_zones' : read-only: designed to show which zones this memory block 174 + can be onlined to. 175 + The first column shows it's default zone. 176 + "memory6/valid_zones: Normal Movable" shows this memoryblock 177 + can be onlined to ZONE_NORMAL by default and to ZONE_MOVABLE 178 + by online_movable. 179 + "memory7/valid_zones: Movable Normal" shows this memoryblock 180 + can be onlined to ZONE_MOVABLE by default and to ZONE_NORMAL 181 + by online_kernel. 174 182 175 183 NOTE: 176 184 These directories/files appear after physical memory hotplug phase. ··· 418 408 - allowing memory hot-add to ZONE_MOVABLE. maybe we need some switch like 419 409 sysctl or new control file. 420 410 - showing memory block and physical device relationship. 421 - - showing memory block is under ZONE_MOVABLE or not 422 411 - test and make it better memory offlining. 423 412 - support HugeTLB page migration and offlining. 424 413 - memmap removing at memory offline.
+42
drivers/base/memory.c
··· 373 373 return sprintf(buf, "%d\n", mem->phys_device); 374 374 } 375 375 376 + #ifdef CONFIG_MEMORY_HOTREMOVE 377 + static ssize_t show_valid_zones(struct device *dev, 378 + struct device_attribute *attr, char *buf) 379 + { 380 + struct memory_block *mem = to_memory_block(dev); 381 + unsigned long start_pfn, end_pfn; 382 + unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; 383 + struct page *first_page; 384 + struct zone *zone; 385 + 386 + start_pfn = section_nr_to_pfn(mem->start_section_nr); 387 + end_pfn = start_pfn + nr_pages; 388 + first_page = pfn_to_page(start_pfn); 389 + 390 + /* The block contains more than one zone can not be offlined. */ 391 + if (!test_pages_in_a_zone(start_pfn, end_pfn)) 392 + return sprintf(buf, "none\n"); 393 + 394 + zone = page_zone(first_page); 395 + 396 + if (zone_idx(zone) == ZONE_MOVABLE - 1) { 397 + /*The mem block is the last memoryblock of this zone.*/ 398 + if (end_pfn == zone_end_pfn(zone)) 399 + return sprintf(buf, "%s %s\n", 400 + zone->name, (zone + 1)->name); 401 + } 402 + 403 + if (zone_idx(zone) == ZONE_MOVABLE) { 404 + /*The mem block is the first memoryblock of ZONE_MOVABLE.*/ 405 + if (start_pfn == zone->zone_start_pfn) 406 + return sprintf(buf, "%s %s\n", 407 + zone->name, (zone - 1)->name); 408 + } 409 + 410 + return sprintf(buf, "%s\n", zone->name); 411 + } 412 + static DEVICE_ATTR(valid_zones, 0444, show_valid_zones, NULL); 413 + #endif 414 + 376 415 static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); 377 416 static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state); 378 417 static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL); ··· 562 523 &dev_attr_state.attr, 563 524 &dev_attr_phys_device.attr, 564 525 &dev_attr_removable.attr, 526 + #ifdef CONFIG_MEMORY_HOTREMOVE 527 + &dev_attr_valid_zones.attr, 528 + #endif 565 529 NULL 566 530 }; 567 531
+1
include/linux/memory_hotplug.h
··· 84 84 extern int add_one_highpage(struct page *page, int pfn, int bad_ppro); 85 85 /* VM interface that may be used by firmware interface */ 86 86 extern int online_pages(unsigned long, unsigned long, int); 87 + extern int test_pages_in_a_zone(unsigned long, unsigned long); 87 88 extern void __offline_isolated_pages(unsigned long, unsigned long); 88 89 89 90 typedef void (*online_page_callback_t)(struct page *page);
+1 -1
mm/memory_hotplug.c
··· 1307 1307 /* 1308 1308 * Confirm all pages in a range [start, end) is belongs to the same zone. 1309 1309 */ 1310 - static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) 1310 + int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) 1311 1311 { 1312 1312 unsigned long pfn; 1313 1313 struct zone *zone = NULL;