diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 91 |
1 files changed, 51 insertions, 40 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 6d59a2bd520a..848b42195e5b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1614,7 +1614,7 @@ void mem_cgroup_update_page_stat(struct page *page, | |||
1614 | if (unlikely(!mem || !PageCgroupUsed(pc))) | 1614 | if (unlikely(!mem || !PageCgroupUsed(pc))) |
1615 | goto out; | 1615 | goto out; |
1616 | /* pc->mem_cgroup is unstable ? */ | 1616 | /* pc->mem_cgroup is unstable ? */ |
1617 | if (unlikely(mem_cgroup_stealed(mem))) { | 1617 | if (unlikely(mem_cgroup_stealed(mem)) || PageTransHuge(page)) { |
1618 | /* take a lock against to access pc->mem_cgroup */ | 1618 | /* take a lock against to access pc->mem_cgroup */ |
1619 | move_lock_page_cgroup(pc, &flags); | 1619 | move_lock_page_cgroup(pc, &flags); |
1620 | need_unlock = true; | 1620 | need_unlock = true; |
@@ -2083,14 +2083,27 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page) | |||
2083 | return mem; | 2083 | return mem; |
2084 | } | 2084 | } |
2085 | 2085 | ||
2086 | /* | 2086 | static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, |
2087 | * commit a charge got by __mem_cgroup_try_charge() and makes page_cgroup to be | 2087 | struct page_cgroup *pc, |
2088 | * USED state. If already USED, uncharge and return. | 2088 | enum charge_type ctype, |
2089 | */ | 2089 | int page_size) |
2090 | static void ____mem_cgroup_commit_charge(struct mem_cgroup *mem, | ||
2091 | struct page_cgroup *pc, | ||
2092 | enum charge_type ctype) | ||
2093 | { | 2090 | { |
2091 | int nr_pages = page_size >> PAGE_SHIFT; | ||
2092 | |||
2093 | /* try_charge() can return NULL to *memcg, taking care of it. */ | ||
2094 | if (!mem) | ||
2095 | return; | ||
2096 | |||
2097 | lock_page_cgroup(pc); | ||
2098 | if (unlikely(PageCgroupUsed(pc))) { | ||
2099 | unlock_page_cgroup(pc); | ||
2100 | mem_cgroup_cancel_charge(mem, page_size); | ||
2101 | return; | ||
2102 | } | ||
2103 | /* | ||
2104 | * we don't need page_cgroup_lock about tail pages, becase they are not | ||
2105 | * accessed by any other context at this point. | ||
2106 | */ | ||
2094 | pc->mem_cgroup = mem; | 2107 | pc->mem_cgroup = mem; |
2095 | /* | 2108 | /* |
2096 | * We access a page_cgroup asynchronously without lock_page_cgroup(). | 2109 | * We access a page_cgroup asynchronously without lock_page_cgroup(). |
@@ -2114,35 +2127,7 @@ static void ____mem_cgroup_commit_charge(struct mem_cgroup *mem, | |||
2114 | break; | 2127 | break; |
2115 | } | 2128 | } |
2116 | 2129 | ||
2117 | mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), 1); | 2130 | mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), nr_pages); |
2118 | } | ||
2119 | |||
2120 | static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, | ||
2121 | struct page_cgroup *pc, | ||
2122 | enum charge_type ctype, | ||
2123 | int page_size) | ||
2124 | { | ||
2125 | int i; | ||
2126 | int count = page_size >> PAGE_SHIFT; | ||
2127 | |||
2128 | /* try_charge() can return NULL to *memcg, taking care of it. */ | ||
2129 | if (!mem) | ||
2130 | return; | ||
2131 | |||
2132 | lock_page_cgroup(pc); | ||
2133 | if (unlikely(PageCgroupUsed(pc))) { | ||
2134 | unlock_page_cgroup(pc); | ||
2135 | mem_cgroup_cancel_charge(mem, page_size); | ||
2136 | return; | ||
2137 | } | ||
2138 | |||
2139 | /* | ||
2140 | * we don't need page_cgroup_lock about tail pages, becase they are not | ||
2141 | * accessed by any other context at this point. | ||
2142 | */ | ||
2143 | for (i = 0; i < count; i++) | ||
2144 | ____mem_cgroup_commit_charge(mem, pc + i, ctype); | ||
2145 | |||
2146 | unlock_page_cgroup(pc); | 2131 | unlock_page_cgroup(pc); |
2147 | /* | 2132 | /* |
2148 | * "charge_statistics" updated event counter. Then, check it. | 2133 | * "charge_statistics" updated event counter. Then, check it. |
@@ -2152,6 +2137,34 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, | |||
2152 | memcg_check_events(mem, pc->page); | 2137 | memcg_check_events(mem, pc->page); |
2153 | } | 2138 | } |
2154 | 2139 | ||
2140 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
2141 | |||
2142 | #define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MOVE_LOCK) |\ | ||
2143 | (1 << PCG_ACCT_LRU) | (1 << PCG_MIGRATION)) | ||
2144 | /* | ||
2145 | * Because tail pages are not marked as "used", set it. We're under | ||
2146 | * zone->lru_lock, 'splitting on pmd' and compund_lock. | ||
2147 | */ | ||
2148 | void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail) | ||
2149 | { | ||
2150 | struct page_cgroup *head_pc = lookup_page_cgroup(head); | ||
2151 | struct page_cgroup *tail_pc = lookup_page_cgroup(tail); | ||
2152 | unsigned long flags; | ||
2153 | |||
2154 | /* | ||
2155 | * We have no races witch charge/uncharge but will have races with | ||
2156 | * page state accounting. | ||
2157 | */ | ||
2158 | move_lock_page_cgroup(head_pc, &flags); | ||
2159 | |||
2160 | tail_pc->mem_cgroup = head_pc->mem_cgroup; | ||
2161 | smp_wmb(); /* see __commit_charge() */ | ||
2162 | /* we don't need to copy all flags...*/ | ||
2163 | tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT; | ||
2164 | move_unlock_page_cgroup(head_pc, &flags); | ||
2165 | } | ||
2166 | #endif | ||
2167 | |||
2155 | /** | 2168 | /** |
2156 | * __mem_cgroup_move_account - move account of the page | 2169 | * __mem_cgroup_move_account - move account of the page |
2157 | * @pc: page_cgroup of the page. | 2170 | * @pc: page_cgroup of the page. |
@@ -2545,7 +2558,6 @@ direct_uncharge: | |||
2545 | static struct mem_cgroup * | 2558 | static struct mem_cgroup * |
2546 | __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) | 2559 | __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) |
2547 | { | 2560 | { |
2548 | int i; | ||
2549 | int count; | 2561 | int count; |
2550 | struct page_cgroup *pc; | 2562 | struct page_cgroup *pc; |
2551 | struct mem_cgroup *mem = NULL; | 2563 | struct mem_cgroup *mem = NULL; |
@@ -2595,8 +2607,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) | |||
2595 | break; | 2607 | break; |
2596 | } | 2608 | } |
2597 | 2609 | ||
2598 | for (i = 0; i < count; i++) | 2610 | mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -count); |
2599 | mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -1); | ||
2600 | 2611 | ||
2601 | ClearPageCgroupUsed(pc); | 2612 | ClearPageCgroupUsed(pc); |
2602 | /* | 2613 | /* |