aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2016-01-15 19:52:20 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-15 20:56:32 -0500
commitf627c2f53786b0445abca47f6aa84c96a1fffec2 (patch)
treea2c0a52a4448ad779d9027c943eb8e1217ae2504 /mm/memcontrol.c
parentd281ee6145183594788ab6d5b55f8d144e69eace (diff)
memcg: adjust to support new THP refcounting
As with rmap, with new refcounting we cannot rely on PageTransHuge() to check if we need to charge size of huge page form the cgroup. We need to get information from caller to know whether it was mapped with PMD or PTE. We do uncharge when last reference on the page gone. At that point if we see PageTransHuge() it means we need to unchange whole huge page. The tricky part is partial unmap -- when we try to unmap part of huge page. We don't do a special handing of this situation, meaning we don't uncharge the part of huge page unless last user is gone or split_huge_page() is triggered. In case of cgroup memory pressure happens the partial unmapped page will be split through shrinker. This should be good enough. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Tested-by: Sasha Levin <sasha.levin@oracle.com> Tested-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Acked-by: Jerome Marchand <jmarchan@redhat.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Rik van Riel <riel@redhat.com> Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Cc: Steve Capper <steve.capper@linaro.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.cz> Cc: Christoph Lameter <cl@linux.com> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c62
1 files changed, 23 insertions, 39 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 54eae4f19d80..311fd2b71bae 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -647,7 +647,7 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
647 647
648static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg, 648static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
649 struct page *page, 649 struct page *page,
650 int nr_pages) 650 bool compound, int nr_pages)
651{ 651{
652 /* 652 /*
653 * Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is 653 * Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is
@@ -660,9 +660,11 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
660 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE], 660 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_CACHE],
661 nr_pages); 661 nr_pages);
662 662
663 if (PageTransHuge(page)) 663 if (compound) {
664 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
664 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE], 665 __this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE],
665 nr_pages); 666 nr_pages);
667 }
666 668
667 /* pagein of a big page is an event. So, ignore page size */ 669 /* pagein of a big page is an event. So, ignore page size */
668 if (nr_pages > 0) 670 if (nr_pages > 0)
@@ -4513,30 +4515,24 @@ static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
4513 * from old cgroup. 4515 * from old cgroup.
4514 */ 4516 */
4515static int mem_cgroup_move_account(struct page *page, 4517static int mem_cgroup_move_account(struct page *page,
4516 unsigned int nr_pages, 4518 bool compound,
4517 struct mem_cgroup *from, 4519 struct mem_cgroup *from,
4518 struct mem_cgroup *to) 4520 struct mem_cgroup *to)
4519{ 4521{
4520 unsigned long flags; 4522 unsigned long flags;
4523 unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
4521 int ret; 4524 int ret;
4522 bool anon; 4525 bool anon;
4523 4526
4524 VM_BUG_ON(from == to); 4527 VM_BUG_ON(from == to);
4525 VM_BUG_ON_PAGE(PageLRU(page), page); 4528 VM_BUG_ON_PAGE(PageLRU(page), page);
4526 /* 4529 VM_BUG_ON(compound && !PageTransHuge(page));
4527 * The page is isolated from LRU. So, collapse function
4528 * will not handle this page. But page splitting can happen.
4529 * Do this check under compound_page_lock(). The caller should
4530 * hold it.
4531 */
4532 ret = -EBUSY;
4533 if (nr_pages > 1 && !PageTransHuge(page))
4534 goto out;
4535 4530
4536 /* 4531 /*
4537 * Prevent mem_cgroup_replace_page() from looking at 4532 * Prevent mem_cgroup_replace_page() from looking at
4538 * page->mem_cgroup of its source page while we change it. 4533 * page->mem_cgroup of its source page while we change it.
4539 */ 4534 */
4535 ret = -EBUSY;
4540 if (!trylock_page(page)) 4536 if (!trylock_page(page))
4541 goto out; 4537 goto out;
4542 4538
@@ -4591,9 +4587,9 @@ static int mem_cgroup_move_account(struct page *page,
4591 ret = 0; 4587 ret = 0;
4592 4588
4593 local_irq_disable(); 4589 local_irq_disable();
4594 mem_cgroup_charge_statistics(to, page, nr_pages); 4590 mem_cgroup_charge_statistics(to, page, compound, nr_pages);
4595 memcg_check_events(to, page); 4591 memcg_check_events(to, page);
4596 mem_cgroup_charge_statistics(from, page, -nr_pages); 4592 mem_cgroup_charge_statistics(from, page, compound, -nr_pages);
4597 memcg_check_events(from, page); 4593 memcg_check_events(from, page);
4598 local_irq_enable(); 4594 local_irq_enable();
4599out_unlock: 4595out_unlock:
@@ -4890,7 +4886,7 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
4890 if (target_type == MC_TARGET_PAGE) { 4886 if (target_type == MC_TARGET_PAGE) {
4891 page = target.page; 4887 page = target.page;
4892 if (!isolate_lru_page(page)) { 4888 if (!isolate_lru_page(page)) {
4893 if (!mem_cgroup_move_account(page, HPAGE_PMD_NR, 4889 if (!mem_cgroup_move_account(page, true,
4894 mc.from, mc.to)) { 4890 mc.from, mc.to)) {
4895 mc.precharge -= HPAGE_PMD_NR; 4891 mc.precharge -= HPAGE_PMD_NR;
4896 mc.moved_charge += HPAGE_PMD_NR; 4892 mc.moved_charge += HPAGE_PMD_NR;
@@ -4919,7 +4915,8 @@ retry:
4919 page = target.page; 4915 page = target.page;
4920 if (isolate_lru_page(page)) 4916 if (isolate_lru_page(page))
4921 goto put; 4917 goto put;
4922 if (!mem_cgroup_move_account(page, 1, mc.from, mc.to)) { 4918 if (!mem_cgroup_move_account(page, false,
4919 mc.from, mc.to)) {
4923 mc.precharge--; 4920 mc.precharge--;
4924 /* we uncharge from mc.from later. */ 4921 /* we uncharge from mc.from later. */
4925 mc.moved_charge++; 4922 mc.moved_charge++;
@@ -5258,10 +5255,11 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
5258 * with mem_cgroup_cancel_charge() in case page instantiation fails. 5255 * with mem_cgroup_cancel_charge() in case page instantiation fails.
5259 */ 5256 */
5260int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm, 5257int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
5261 gfp_t gfp_mask, struct mem_cgroup **memcgp) 5258 gfp_t gfp_mask, struct mem_cgroup **memcgp,
5259 bool compound)
5262{ 5260{
5263 struct mem_cgroup *memcg = NULL; 5261 struct mem_cgroup *memcg = NULL;
5264 unsigned int nr_pages = 1; 5262 unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
5265 int ret = 0; 5263 int ret = 0;
5266 5264
5267 if (mem_cgroup_disabled()) 5265 if (mem_cgroup_disabled())
@@ -5291,11 +5289,6 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
5291 } 5289 }
5292 } 5290 }
5293 5291
5294 if (PageTransHuge(page)) {
5295 nr_pages <<= compound_order(page);
5296 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
5297 }
5298
5299 if (!memcg) 5292 if (!memcg)
5300 memcg = get_mem_cgroup_from_mm(mm); 5293 memcg = get_mem_cgroup_from_mm(mm);
5301 5294
@@ -5324,9 +5317,9 @@ out:
5324 * Use mem_cgroup_cancel_charge() to cancel the transaction instead. 5317 * Use mem_cgroup_cancel_charge() to cancel the transaction instead.
5325 */ 5318 */
5326void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg, 5319void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
5327 bool lrucare) 5320 bool lrucare, bool compound)
5328{ 5321{
5329 unsigned int nr_pages = 1; 5322 unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
5330 5323
5331 VM_BUG_ON_PAGE(!page->mapping, page); 5324 VM_BUG_ON_PAGE(!page->mapping, page);
5332 VM_BUG_ON_PAGE(PageLRU(page) && !lrucare, page); 5325 VM_BUG_ON_PAGE(PageLRU(page) && !lrucare, page);
@@ -5343,13 +5336,8 @@ void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
5343 5336
5344 commit_charge(page, memcg, lrucare); 5337 commit_charge(page, memcg, lrucare);
5345 5338
5346 if (PageTransHuge(page)) {
5347 nr_pages <<= compound_order(page);
5348 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
5349 }
5350
5351 local_irq_disable(); 5339 local_irq_disable();
5352 mem_cgroup_charge_statistics(memcg, page, nr_pages); 5340 mem_cgroup_charge_statistics(memcg, page, compound, nr_pages);
5353 memcg_check_events(memcg, page); 5341 memcg_check_events(memcg, page);
5354 local_irq_enable(); 5342 local_irq_enable();
5355 5343
@@ -5371,9 +5359,10 @@ void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
5371 * 5359 *
5372 * Cancel a charge transaction started by mem_cgroup_try_charge(). 5360 * Cancel a charge transaction started by mem_cgroup_try_charge().
5373 */ 5361 */
5374void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg) 5362void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg,
5363 bool compound)
5375{ 5364{
5376 unsigned int nr_pages = 1; 5365 unsigned int nr_pages = compound ? hpage_nr_pages(page) : 1;
5377 5366
5378 if (mem_cgroup_disabled()) 5367 if (mem_cgroup_disabled())
5379 return; 5368 return;
@@ -5385,11 +5374,6 @@ void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg)
5385 if (!memcg) 5374 if (!memcg)
5386 return; 5375 return;
5387 5376
5388 if (PageTransHuge(page)) {
5389 nr_pages <<= compound_order(page);
5390 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
5391 }
5392
5393 cancel_charge(memcg, nr_pages); 5377 cancel_charge(memcg, nr_pages);
5394} 5378}
5395 5379
@@ -5750,7 +5734,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
5750 * only synchronisation we have for udpating the per-CPU variables. 5734 * only synchronisation we have for udpating the per-CPU variables.
5751 */ 5735 */
5752 VM_BUG_ON(!irqs_disabled()); 5736 VM_BUG_ON(!irqs_disabled());
5753 mem_cgroup_charge_statistics(memcg, page, -1); 5737 mem_cgroup_charge_statistics(memcg, page, false, -1);
5754 memcg_check_events(memcg, page); 5738 memcg_check_events(memcg, page);
5755} 5739}
5756 5740