diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 848b42195e5b..7a94ef6b35e2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -814,7 +814,8 @@ void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru) | |||
814 | * removed from global LRU. | 814 | * removed from global LRU. |
815 | */ | 815 | */ |
816 | mz = page_cgroup_zoneinfo(pc); | 816 | mz = page_cgroup_zoneinfo(pc); |
817 | MEM_CGROUP_ZSTAT(mz, lru) -= 1; | 817 | /* huge page split is done under lru_lock. so, we have no races. */ |
818 | MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page); | ||
818 | if (mem_cgroup_is_root(pc->mem_cgroup)) | 819 | if (mem_cgroup_is_root(pc->mem_cgroup)) |
819 | return; | 820 | return; |
820 | VM_BUG_ON(list_empty(&pc->lru)); | 821 | VM_BUG_ON(list_empty(&pc->lru)); |
@@ -865,7 +866,8 @@ void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru) | |||
865 | return; | 866 | return; |
866 | 867 | ||
867 | mz = page_cgroup_zoneinfo(pc); | 868 | mz = page_cgroup_zoneinfo(pc); |
868 | MEM_CGROUP_ZSTAT(mz, lru) += 1; | 869 | /* huge page split is done under lru_lock. so, we have no races. */ |
870 | MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page); | ||
869 | SetPageCgroupAcctLRU(pc); | 871 | SetPageCgroupAcctLRU(pc); |
870 | if (mem_cgroup_is_root(pc->mem_cgroup)) | 872 | if (mem_cgroup_is_root(pc->mem_cgroup)) |
871 | return; | 873 | return; |
@@ -2152,14 +2154,26 @@ void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail) | |||
2152 | unsigned long flags; | 2154 | unsigned long flags; |
2153 | 2155 | ||
2154 | /* | 2156 | /* |
2155 | * We have no races witch charge/uncharge but will have races with | 2157 | * We have no races with charge/uncharge but will have races with |
2156 | * page state accounting. | 2158 | * page state accounting. |
2157 | */ | 2159 | */ |
2158 | move_lock_page_cgroup(head_pc, &flags); | 2160 | move_lock_page_cgroup(head_pc, &flags); |
2159 | 2161 | ||
2160 | tail_pc->mem_cgroup = head_pc->mem_cgroup; | 2162 | tail_pc->mem_cgroup = head_pc->mem_cgroup; |
2161 | smp_wmb(); /* see __commit_charge() */ | 2163 | smp_wmb(); /* see __commit_charge() */ |
2162 | /* we don't need to copy all flags...*/ | 2164 | if (PageCgroupAcctLRU(head_pc)) { |
2165 | enum lru_list lru; | ||
2166 | struct mem_cgroup_per_zone *mz; | ||
2167 | |||
2168 | /* | ||
2169 | * LRU flags cannot be copied because we need to add tail | ||
2170 | *.page to LRU by generic call and our hook will be called. | ||
2171 | * We hold lru_lock, then, reduce counter directly. | ||
2172 | */ | ||
2173 | lru = page_lru(head); | ||
2174 | mz = page_cgroup_zoneinfo(head_pc); | ||
2175 | MEM_CGROUP_ZSTAT(mz, lru) -= 1; | ||
2176 | } | ||
2163 | tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT; | 2177 | tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT; |
2164 | move_unlock_page_cgroup(head_pc, &flags); | 2178 | move_unlock_page_cgroup(head_pc, &flags); |
2165 | } | 2179 | } |