diff options
author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2012-12-11 19:03:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 20:22:28 -0500 |
commit | 511c2aba8f07fc45bdcba548cb63f7b8a450c6dc (patch) | |
tree | 6a1a853e60e0004f5895d78231ed1bea33fecaac /drivers/base/memory.c | |
parent | fcf07d22f089856631b52a75c35ba3c33b70a1b4 (diff) |
mm, memory-hotplug: dynamic configure movable memory and portion memory
Add online_movable and online_kernel for logic memory hotplug. This is
the dynamic version of "movablecore" & "kernelcore".
We have the same reason to introduce it as to introduce "movablecore" &
"kernelcore". It has the same motive as "movablecore" & "kernelcore", but
it is dynamic/running-time:
o We can configure memory as kernelcore or movablecore after boot.
Userspace workload is increased, we need more hugepage, we can't use
"online_movable" to add memory and allow the system use more
THP(transparent-huge-page), vice-verse when kernel workload is increase.
Also help for virtualization to dynamic configure host/guest's memory,
to save/(reduce waste) memory.
Memory capacity on Demand
o When a new node is physically online after boot, we need to use
"online_movable" or "online_kernel" to configure/portion it as we
expected when we logic-online it.
This configuration also helps for physically-memory-migrate.
o all benefit as the same as existed "movablecore" & "kernelcore".
o Preparing for movable-node, which is very important for power-saving,
hardware partitioning and high-available-system(hardware fault
management).
(Note, we don't introduce movable-node here.)
Action behavior:
When a memoryblock/memorysection is onlined by "online_movable", the kernel
will not have directly reference to the page of the memoryblock,
thus we can remove that memory any time when needed.
When it is online by "online_kernel", the kernel can use it.
When it is online by "online", the zone type doesn't changed.
Current constraints:
Only the memoryblock which is adjacent to the ZONE_MOVABLE
can be online from ZONE_NORMAL to ZONE_MOVABLE.
[akpm@linux-foundation.org: use min_t, cleanups]
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Cc: Jiang Liu <jiang.liu@huawei.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: David Rientjes <rientjes@google.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/base/memory.c')
-rw-r--r-- | drivers/base/memory.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 7eb1211ab688..987604d56c83 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -254,7 +254,7 @@ static bool pages_correctly_reserved(unsigned long start_pfn, | |||
254 | * OK to have direct references to sparsemem variables in here. | 254 | * OK to have direct references to sparsemem variables in here. |
255 | */ | 255 | */ |
256 | static int | 256 | static int |
257 | memory_block_action(unsigned long phys_index, unsigned long action) | 257 | memory_block_action(unsigned long phys_index, unsigned long action, int online_type) |
258 | { | 258 | { |
259 | unsigned long start_pfn; | 259 | unsigned long start_pfn; |
260 | unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; | 260 | unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; |
@@ -269,7 +269,7 @@ memory_block_action(unsigned long phys_index, unsigned long action) | |||
269 | if (!pages_correctly_reserved(start_pfn, nr_pages)) | 269 | if (!pages_correctly_reserved(start_pfn, nr_pages)) |
270 | return -EBUSY; | 270 | return -EBUSY; |
271 | 271 | ||
272 | ret = online_pages(start_pfn, nr_pages); | 272 | ret = online_pages(start_pfn, nr_pages, online_type); |
273 | break; | 273 | break; |
274 | case MEM_OFFLINE: | 274 | case MEM_OFFLINE: |
275 | ret = offline_pages(start_pfn, nr_pages); | 275 | ret = offline_pages(start_pfn, nr_pages); |
@@ -284,7 +284,8 @@ memory_block_action(unsigned long phys_index, unsigned long action) | |||
284 | } | 284 | } |
285 | 285 | ||
286 | static int __memory_block_change_state(struct memory_block *mem, | 286 | static int __memory_block_change_state(struct memory_block *mem, |
287 | unsigned long to_state, unsigned long from_state_req) | 287 | unsigned long to_state, unsigned long from_state_req, |
288 | int online_type) | ||
288 | { | 289 | { |
289 | int ret = 0; | 290 | int ret = 0; |
290 | 291 | ||
@@ -296,7 +297,7 @@ static int __memory_block_change_state(struct memory_block *mem, | |||
296 | if (to_state == MEM_OFFLINE) | 297 | if (to_state == MEM_OFFLINE) |
297 | mem->state = MEM_GOING_OFFLINE; | 298 | mem->state = MEM_GOING_OFFLINE; |
298 | 299 | ||
299 | ret = memory_block_action(mem->start_section_nr, to_state); | 300 | ret = memory_block_action(mem->start_section_nr, to_state, online_type); |
300 | 301 | ||
301 | if (ret) { | 302 | if (ret) { |
302 | mem->state = from_state_req; | 303 | mem->state = from_state_req; |
@@ -319,12 +320,14 @@ out: | |||
319 | } | 320 | } |
320 | 321 | ||
321 | static int memory_block_change_state(struct memory_block *mem, | 322 | static int memory_block_change_state(struct memory_block *mem, |
322 | unsigned long to_state, unsigned long from_state_req) | 323 | unsigned long to_state, unsigned long from_state_req, |
324 | int online_type) | ||
323 | { | 325 | { |
324 | int ret; | 326 | int ret; |
325 | 327 | ||
326 | mutex_lock(&mem->state_mutex); | 328 | mutex_lock(&mem->state_mutex); |
327 | ret = __memory_block_change_state(mem, to_state, from_state_req); | 329 | ret = __memory_block_change_state(mem, to_state, from_state_req, |
330 | online_type); | ||
328 | mutex_unlock(&mem->state_mutex); | 331 | mutex_unlock(&mem->state_mutex); |
329 | 332 | ||
330 | return ret; | 333 | return ret; |
@@ -338,10 +341,18 @@ store_mem_state(struct device *dev, | |||
338 | 341 | ||
339 | mem = container_of(dev, struct memory_block, dev); | 342 | mem = container_of(dev, struct memory_block, dev); |
340 | 343 | ||
341 | if (!strncmp(buf, "online", min((int)count, 6))) | 344 | if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) |
342 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); | 345 | ret = memory_block_change_state(mem, MEM_ONLINE, |
343 | else if(!strncmp(buf, "offline", min((int)count, 7))) | 346 | MEM_OFFLINE, ONLINE_KERNEL); |
344 | ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); | 347 | else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) |
348 | ret = memory_block_change_state(mem, MEM_ONLINE, | ||
349 | MEM_OFFLINE, ONLINE_MOVABLE); | ||
350 | else if (!strncmp(buf, "online", min_t(int, count, 6))) | ||
351 | ret = memory_block_change_state(mem, MEM_ONLINE, | ||
352 | MEM_OFFLINE, ONLINE_KEEP); | ||
353 | else if(!strncmp(buf, "offline", min_t(int, count, 7))) | ||
354 | ret = memory_block_change_state(mem, MEM_OFFLINE, | ||
355 | MEM_ONLINE, -1); | ||
345 | 356 | ||
346 | if (ret) | 357 | if (ret) |
347 | return ret; | 358 | return ret; |
@@ -676,7 +687,7 @@ int offline_memory_block(struct memory_block *mem) | |||
676 | 687 | ||
677 | mutex_lock(&mem->state_mutex); | 688 | mutex_lock(&mem->state_mutex); |
678 | if (mem->state != MEM_OFFLINE) | 689 | if (mem->state != MEM_OFFLINE) |
679 | ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); | 690 | ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1); |
680 | mutex_unlock(&mem->state_mutex); | 691 | mutex_unlock(&mem->state_mutex); |
681 | 692 | ||
682 | return ret; | 693 | return ret; |