aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory.c
diff options
context:
space:
mode:
authorKonstantin Khlebnikov <khlebnikov@openvz.org>2012-01-20 17:34:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-23 11:38:49 -0500
commit9f9f1acd713d69fae2af286fbeedc6c8963411c6 (patch)
treecfa1485d01cb36c720f1e2b96b21748acc10ec06 /mm/memory.c
parent245132643e1cfcd145bbc86a716c1818371fcb93 (diff)
mm: fix rss count leakage during migration
Memory migration fills a pte with a migration entry and it doesn't update the rss counters. Then it replaces the migration entry with the new page (or the old one if migration failed). But between these two passes this pte can be unmaped, or a task can fork a child and it will get a copy of this migration entry. Nobody accounts for this in the rss counters. This patch properly adjust rss counters for migration entries in zap_pte_range() and copy_one_pte(). Thus we avoid extra atomic operations on the migration fast-path. Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org> Cc: Hugh Dickins <hughd@google.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memory.c')
-rw-r--r--mm/memory.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/mm/memory.c b/mm/memory.c
index 5e30583c260..fa2f04e0337 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -878,15 +878,24 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
878 } 878 }
879 if (likely(!non_swap_entry(entry))) 879 if (likely(!non_swap_entry(entry)))
880 rss[MM_SWAPENTS]++; 880 rss[MM_SWAPENTS]++;
881 else if (is_write_migration_entry(entry) && 881 else if (is_migration_entry(entry)) {
882 is_cow_mapping(vm_flags)) { 882 page = migration_entry_to_page(entry);
883 /* 883
884 * COW mappings require pages in both parent 884 if (PageAnon(page))
885 * and child to be set to read. 885 rss[MM_ANONPAGES]++;
886 */ 886 else
887 make_migration_entry_read(&entry); 887 rss[MM_FILEPAGES]++;
888 pte = swp_entry_to_pte(entry); 888
889 set_pte_at(src_mm, addr, src_pte, pte); 889 if (is_write_migration_entry(entry) &&
890 is_cow_mapping(vm_flags)) {
891 /*
892 * COW mappings require pages in both
893 * parent and child to be set to read.
894 */
895 make_migration_entry_read(&entry);
896 pte = swp_entry_to_pte(entry);
897 set_pte_at(src_mm, addr, src_pte, pte);
898 }
890 } 899 }
891 } 900 }
892 goto out_set_pte; 901 goto out_set_pte;
@@ -1191,6 +1200,16 @@ again:
1191 1200
1192 if (!non_swap_entry(entry)) 1201 if (!non_swap_entry(entry))
1193 rss[MM_SWAPENTS]--; 1202 rss[MM_SWAPENTS]--;
1203 else if (is_migration_entry(entry)) {
1204 struct page *page;
1205
1206 page = migration_entry_to_page(entry);
1207
1208 if (PageAnon(page))
1209 rss[MM_ANONPAGES]--;
1210 else
1211 rss[MM_FILEPAGES]--;
1212 }
1194 if (unlikely(!free_swap_and_cache(entry))) 1213 if (unlikely(!free_swap_and_cache(entry)))
1195 print_bad_pte(vma, addr, ptent, NULL); 1214 print_bad_pte(vma, addr, ptent, NULL);
1196 } 1215 }