aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Aquini <aquini@redhat.com>2012-12-11 19:02:31 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-11 20:22:26 -0500
commit78bd52097d04205a33a8014a1b8ac01cf1ae9d06 (patch)
tree4f86e6e56a9e3a3d49e9c46042b3ce980cc04dbc
parent748ba883ba2818890a73461ef7dde1eed17ad89f (diff)
mm: adjust address_space_operations.migratepage() return code
Memory fragmentation introduced by ballooning might reduce significantly the number of 2MB contiguous memory blocks that can be used within a guest, thus imposing performance penalties associated with the reduced number of transparent huge pages that could be used by the guest workload. This patch-set follows the main idea discussed at 2012 LSFMMS session: "Ballooning for transparent huge pages" -- http://lwn.net/Articles/490114/ to introduce the required changes to the virtio_balloon driver, as well as the changes to the core compaction & migration bits, in order to make those subsystems aware of ballooned pages and allow memory balloon pages become movable within a guest, thus avoiding the aforementioned fragmentation issue Following are numbers that prove this patch benefits on allowing compaction to be more effective at memory ballooned guests. Results for STRESS-HIGHALLOC benchmark, from Mel Gorman's mmtests suite, running on a 4gB RAM KVM guest which was ballooning 512mB RAM in 64mB chunks, at every minute (inflating/deflating), while test was running: ===BEGIN stress-highalloc STRESS-HIGHALLOC highalloc-3.7 highalloc-3.7 rc4-clean rc4-patch Pass 1 55.00 ( 0.00%) 62.00 ( 7.00%) Pass 2 54.00 ( 0.00%) 62.00 ( 8.00%) while Rested 75.00 ( 0.00%) 80.00 ( 5.00%) MMTests Statistics: duration 3.7 3.7 rc4-clean rc4-patch User 1207.59 1207.46 System 1300.55 1299.61 Elapsed 2273.72 2157.06 MMTests Statistics: vmstat 3.7 3.7 rc4-clean rc4-patch Page Ins 3581516 2374368 Page Outs 11148692 10410332 Swap Ins 80 47 Swap Outs 3641 476 Direct pages scanned 37978 33826 Kswapd pages scanned 1828245 1342869 Kswapd pages reclaimed 1710236 1304099 Direct pages reclaimed 32207 31005 Kswapd efficiency 93% 97% Kswapd velocity 804.077 622.546 Direct efficiency 84% 91% Direct velocity 16.703 15.682 Percentage direct scans 2% 2% Page writes by reclaim 79252 9704 Page writes file 75611 9228 Page writes anon 3641 476 Page reclaim immediate 16764 11014 Page rescued immediate 0 0 Slabs scanned 2171904 2152448 Direct inode steals 385 2261 Kswapd inode steals 659137 609670 Kswapd skipped wait 1 69 THP fault alloc 546 631 THP collapse alloc 361 339 THP splits 259 263 THP fault fallback 98 50 THP collapse fail 20 17 Compaction stalls 747 499 Compaction success 244 145 Compaction failures 503 354 Compaction pages moved 370888 474837 Compaction move failure 77378 65259 ===END stress-highalloc This patch: Introduce MIGRATEPAGE_SUCCESS as the default return code for address_space_operations.migratepage() method and documents the expected return code for the same method in failure cases. Signed-off-by: Rafael Aquini <aquini@redhat.com> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: "Michael S. Tsirkin" <mst@redhat.com> Cc: Rik van Riel <riel@redhat.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Andi Kleen <andi@firstfloor.org> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Minchan Kim <minchan@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/hugetlbfs/inode.c4
-rw-r--r--include/linux/migrate.h7
-rw-r--r--mm/migrate.c33
3 files changed, 24 insertions, 20 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 47e6e2f21e21..4a55f35a6ced 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -582,11 +582,11 @@ static int hugetlbfs_migrate_page(struct address_space *mapping,
582 int rc; 582 int rc;
583 583
584 rc = migrate_huge_page_move_mapping(mapping, newpage, page); 584 rc = migrate_huge_page_move_mapping(mapping, newpage, page);
585 if (rc) 585 if (rc != MIGRATEPAGE_SUCCESS)
586 return rc; 586 return rc;
587 migrate_page_copy(newpage, page); 587 migrate_page_copy(newpage, page);
588 588
589 return 0; 589 return MIGRATEPAGE_SUCCESS;
590} 590}
591 591
592static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf) 592static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index ce7e6671968b..a4e886d17f87 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -7,6 +7,13 @@
7 7
8typedef struct page *new_page_t(struct page *, unsigned long private, int **); 8typedef struct page *new_page_t(struct page *, unsigned long private, int **);
9 9
10/*
11 * Return values from addresss_space_operations.migratepage():
12 * - negative errno on page migration failure;
13 * - zero on page migration success;
14 */
15#define MIGRATEPAGE_SUCCESS 0
16
10#ifdef CONFIG_MIGRATION 17#ifdef CONFIG_MIGRATION
11 18
12extern void putback_lru_pages(struct list_head *l); 19extern void putback_lru_pages(struct list_head *l);
diff --git a/mm/migrate.c b/mm/migrate.c
index 1dc4598d2513..33f5f82a6006 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -276,7 +276,7 @@ static int migrate_page_move_mapping(struct address_space *mapping,
276 /* Anonymous page without mapping */ 276 /* Anonymous page without mapping */
277 if (page_count(page) != 1) 277 if (page_count(page) != 1)
278 return -EAGAIN; 278 return -EAGAIN;
279 return 0; 279 return MIGRATEPAGE_SUCCESS;
280 } 280 }
281 281
282 spin_lock_irq(&mapping->tree_lock); 282 spin_lock_irq(&mapping->tree_lock);
@@ -346,7 +346,7 @@ static int migrate_page_move_mapping(struct address_space *mapping,
346 } 346 }
347 spin_unlock_irq(&mapping->tree_lock); 347 spin_unlock_irq(&mapping->tree_lock);
348 348
349 return 0; 349 return MIGRATEPAGE_SUCCESS;
350} 350}
351 351
352/* 352/*
@@ -362,7 +362,7 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
362 if (!mapping) { 362 if (!mapping) {
363 if (page_count(page) != 1) 363 if (page_count(page) != 1)
364 return -EAGAIN; 364 return -EAGAIN;
365 return 0; 365 return MIGRATEPAGE_SUCCESS;
366 } 366 }
367 367
368 spin_lock_irq(&mapping->tree_lock); 368 spin_lock_irq(&mapping->tree_lock);
@@ -389,7 +389,7 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
389 page_unfreeze_refs(page, expected_count - 1); 389 page_unfreeze_refs(page, expected_count - 1);
390 390
391 spin_unlock_irq(&mapping->tree_lock); 391 spin_unlock_irq(&mapping->tree_lock);
392 return 0; 392 return MIGRATEPAGE_SUCCESS;
393} 393}
394 394
395/* 395/*
@@ -476,11 +476,11 @@ int migrate_page(struct address_space *mapping,
476 476
477 rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode); 477 rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode);
478 478
479 if (rc) 479 if (rc != MIGRATEPAGE_SUCCESS)
480 return rc; 480 return rc;
481 481
482 migrate_page_copy(newpage, page); 482 migrate_page_copy(newpage, page);
483 return 0; 483 return MIGRATEPAGE_SUCCESS;
484} 484}
485EXPORT_SYMBOL(migrate_page); 485EXPORT_SYMBOL(migrate_page);
486 486
@@ -503,7 +503,7 @@ int buffer_migrate_page(struct address_space *mapping,
503 503
504 rc = migrate_page_move_mapping(mapping, newpage, page, head, mode); 504 rc = migrate_page_move_mapping(mapping, newpage, page, head, mode);
505 505
506 if (rc) 506 if (rc != MIGRATEPAGE_SUCCESS)
507 return rc; 507 return rc;
508 508
509 /* 509 /*
@@ -539,7 +539,7 @@ int buffer_migrate_page(struct address_space *mapping,
539 539
540 } while (bh != head); 540 } while (bh != head);
541 541
542 return 0; 542 return MIGRATEPAGE_SUCCESS;
543} 543}
544EXPORT_SYMBOL(buffer_migrate_page); 544EXPORT_SYMBOL(buffer_migrate_page);
545#endif 545#endif
@@ -618,7 +618,7 @@ static int fallback_migrate_page(struct address_space *mapping,
618 * 618 *
619 * Return value: 619 * Return value:
620 * < 0 - error code 620 * < 0 - error code
621 * == 0 - success 621 * MIGRATEPAGE_SUCCESS - success
622 */ 622 */
623static int move_to_new_page(struct page *newpage, struct page *page, 623static int move_to_new_page(struct page *newpage, struct page *page,
624 int remap_swapcache, enum migrate_mode mode) 624 int remap_swapcache, enum migrate_mode mode)
@@ -655,7 +655,7 @@ static int move_to_new_page(struct page *newpage, struct page *page,
655 else 655 else
656 rc = fallback_migrate_page(mapping, newpage, page, mode); 656 rc = fallback_migrate_page(mapping, newpage, page, mode);
657 657
658 if (rc) { 658 if (rc != MIGRATEPAGE_SUCCESS) {
659 newpage->mapping = NULL; 659 newpage->mapping = NULL;
660 } else { 660 } else {
661 if (remap_swapcache) 661 if (remap_swapcache)
@@ -804,7 +804,7 @@ skip_unmap:
804 put_anon_vma(anon_vma); 804 put_anon_vma(anon_vma);
805 805
806uncharge: 806uncharge:
807 mem_cgroup_end_migration(mem, page, newpage, rc == 0); 807 mem_cgroup_end_migration(mem, page, newpage, rc == MIGRATEPAGE_SUCCESS);
808unlock: 808unlock:
809 unlock_page(page); 809 unlock_page(page);
810out: 810out:
@@ -977,7 +977,7 @@ int migrate_pages(struct list_head *from,
977 case -EAGAIN: 977 case -EAGAIN:
978 retry++; 978 retry++;
979 break; 979 break;
980 case 0: 980 case MIGRATEPAGE_SUCCESS:
981 break; 981 break;
982 default: 982 default:
983 /* Permanent failure */ 983 /* Permanent failure */
@@ -986,15 +986,12 @@ int migrate_pages(struct list_head *from,
986 } 986 }
987 } 987 }
988 } 988 }
989 rc = 0; 989 rc = nr_failed + retry;
990out: 990out:
991 if (!swapwrite) 991 if (!swapwrite)
992 current->flags &= ~PF_SWAPWRITE; 992 current->flags &= ~PF_SWAPWRITE;
993 993
994 if (rc) 994 return rc;
995 return rc;
996
997 return nr_failed + retry;
998} 995}
999 996
1000int migrate_huge_page(struct page *hpage, new_page_t get_new_page, 997int migrate_huge_page(struct page *hpage, new_page_t get_new_page,
@@ -1014,7 +1011,7 @@ int migrate_huge_page(struct page *hpage, new_page_t get_new_page,
1014 /* try again */ 1011 /* try again */
1015 cond_resched(); 1012 cond_resched();
1016 break; 1013 break;
1017 case 0: 1014 case MIGRATEPAGE_SUCCESS:
1018 goto out; 1015 goto out;
1019 default: 1016 default:
1020 rc = -EIO; 1017 rc = -EIO;