Commit bbc76be67c2c0c12548937a07ea3643c32a95b8c
Committed by
Linus Torvalds
1 parent
6677e3eaf4
Exists in
master
and in
20 other branches
memory-hotplug: remove redundant codes
offlining memory blocks and checking whether memory blocks are offlined are very similar. This patch introduces a new function to remove redundant codes. Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com> Reviewed-by: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Jiang Liu <jiang.liu@huawei.com> Cc: Jianguo Wu <wujianguo@huawei.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Wu Jianguo <wujianguo@huawei.com> Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 82 additions and 47 deletions Side-by-side Diff
mm/memory_hotplug.c
... | ... | @@ -1380,20 +1380,26 @@ |
1380 | 1380 | return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ); |
1381 | 1381 | } |
1382 | 1382 | |
1383 | -int remove_memory(u64 start, u64 size) | |
1383 | +/** | |
1384 | + * walk_memory_range - walks through all mem sections in [start_pfn, end_pfn) | |
1385 | + * @start_pfn: start pfn of the memory range | |
1386 | + * @end_pfn: end pft of the memory range | |
1387 | + * @arg: argument passed to func | |
1388 | + * @func: callback for each memory section walked | |
1389 | + * | |
1390 | + * This function walks through all present mem sections in range | |
1391 | + * [start_pfn, end_pfn) and call func on each mem section. | |
1392 | + * | |
1393 | + * Returns the return value of func. | |
1394 | + */ | |
1395 | +static int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, | |
1396 | + void *arg, int (*func)(struct memory_block *, void *)) | |
1384 | 1397 | { |
1385 | 1398 | struct memory_block *mem = NULL; |
1386 | 1399 | struct mem_section *section; |
1387 | - unsigned long start_pfn, end_pfn; | |
1388 | 1400 | unsigned long pfn, section_nr; |
1389 | 1401 | int ret; |
1390 | - int return_on_error = 0; | |
1391 | - int retry = 0; | |
1392 | 1402 | |
1393 | - start_pfn = PFN_DOWN(start); | |
1394 | - end_pfn = start_pfn + PFN_DOWN(size); | |
1395 | - | |
1396 | -repeat: | |
1397 | 1403 | for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { |
1398 | 1404 | section_nr = pfn_to_section_nr(pfn); |
1399 | 1405 | if (!present_section_nr(section_nr)) |
1400 | 1406 | |
1401 | 1407 | |
... | ... | @@ -1410,22 +1416,76 @@ |
1410 | 1416 | if (!mem) |
1411 | 1417 | continue; |
1412 | 1418 | |
1413 | - ret = offline_memory_block(mem); | |
1419 | + ret = func(mem, arg); | |
1414 | 1420 | if (ret) { |
1415 | - if (return_on_error) { | |
1416 | - kobject_put(&mem->dev.kobj); | |
1417 | - return ret; | |
1418 | - } else { | |
1419 | - retry = 1; | |
1420 | - } | |
1421 | + kobject_put(&mem->dev.kobj); | |
1422 | + return ret; | |
1421 | 1423 | } |
1422 | 1424 | } |
1423 | 1425 | |
1424 | 1426 | if (mem) |
1425 | 1427 | kobject_put(&mem->dev.kobj); |
1426 | 1428 | |
1427 | - if (retry) { | |
1428 | - return_on_error = 1; | |
1429 | + return 0; | |
1430 | +} | |
1431 | + | |
1432 | +/** | |
1433 | + * offline_memory_block_cb - callback function for offlining memory block | |
1434 | + * @mem: the memory block to be offlined | |
1435 | + * @arg: buffer to hold error msg | |
1436 | + * | |
1437 | + * Always return 0, and put the error msg in arg if any. | |
1438 | + */ | |
1439 | +static int offline_memory_block_cb(struct memory_block *mem, void *arg) | |
1440 | +{ | |
1441 | + int *ret = arg; | |
1442 | + int error = offline_memory_block(mem); | |
1443 | + | |
1444 | + if (error != 0 && *ret == 0) | |
1445 | + *ret = error; | |
1446 | + | |
1447 | + return 0; | |
1448 | +} | |
1449 | + | |
1450 | +static int is_memblock_offlined_cb(struct memory_block *mem, void *arg) | |
1451 | +{ | |
1452 | + int ret = !is_memblock_offlined(mem); | |
1453 | + | |
1454 | + if (unlikely(ret)) | |
1455 | + pr_warn("removing memory fails, because memory " | |
1456 | + "[%#010llx-%#010llx] is onlined\n", | |
1457 | + PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)), | |
1458 | + PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1))-1); | |
1459 | + | |
1460 | + return ret; | |
1461 | +} | |
1462 | + | |
1463 | +int remove_memory(u64 start, u64 size) | |
1464 | +{ | |
1465 | + unsigned long start_pfn, end_pfn; | |
1466 | + int ret = 0; | |
1467 | + int retry = 1; | |
1468 | + | |
1469 | + start_pfn = PFN_DOWN(start); | |
1470 | + end_pfn = start_pfn + PFN_DOWN(size); | |
1471 | + | |
1472 | + /* | |
1473 | + * When CONFIG_MEMCG is on, one memory block may be used by other | |
1474 | + * blocks to store page cgroup when onlining pages. But we don't know | |
1475 | + * in what order pages are onlined. So we iterate twice to offline | |
1476 | + * memory: | |
1477 | + * 1st iterate: offline every non primary memory block. | |
1478 | + * 2nd iterate: offline primary (i.e. first added) memory block. | |
1479 | + */ | |
1480 | +repeat: | |
1481 | + walk_memory_range(start_pfn, end_pfn, &ret, | |
1482 | + offline_memory_block_cb); | |
1483 | + if (ret) { | |
1484 | + if (!retry) | |
1485 | + return ret; | |
1486 | + | |
1487 | + retry = 0; | |
1488 | + ret = 0; | |
1429 | 1489 | goto repeat; |
1430 | 1490 | } |
1431 | 1491 | |
1432 | 1492 | |
... | ... | @@ -1443,38 +1503,13 @@ |
1443 | 1503 | * memory blocks are offlined. |
1444 | 1504 | */ |
1445 | 1505 | |
1446 | - mem = NULL; | |
1447 | - for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { | |
1448 | - section_nr = pfn_to_section_nr(pfn); | |
1449 | - if (!present_section_nr(section_nr)) | |
1450 | - continue; | |
1451 | - | |
1452 | - section = __nr_to_section(section_nr); | |
1453 | - /* same memblock? */ | |
1454 | - if (mem) | |
1455 | - if ((section_nr >= mem->start_section_nr) && | |
1456 | - (section_nr <= mem->end_section_nr)) | |
1457 | - continue; | |
1458 | - | |
1459 | - mem = find_memory_block_hinted(section, mem); | |
1460 | - if (!mem) | |
1461 | - continue; | |
1462 | - | |
1463 | - ret = is_memblock_offlined(mem); | |
1464 | - if (!ret) { | |
1465 | - pr_warn("removing memory fails, because memory " | |
1466 | - "[%#010llx-%#010llx] is onlined\n", | |
1467 | - PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)), | |
1468 | - PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1)) - 1); | |
1469 | - | |
1470 | - kobject_put(&mem->dev.kobj); | |
1471 | - unlock_memory_hotplug(); | |
1472 | - return ret; | |
1473 | - } | |
1506 | + ret = walk_memory_range(start_pfn, end_pfn, NULL, | |
1507 | + is_memblock_offlined_cb); | |
1508 | + if (ret) { | |
1509 | + unlock_memory_hotplug(); | |
1510 | + return ret; | |
1474 | 1511 | } |
1475 | 1512 | |
1476 | - if (mem) | |
1477 | - kobject_put(&mem->dev.kobj); | |
1478 | 1513 | unlock_memory_hotplug(); |
1479 | 1514 | |
1480 | 1515 | return 0; |