diff options
author | Johannes Weiner <hannes@cmpxchg.org> | 2011-03-23 19:42:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-23 22:46:30 -0400 |
commit | 7ec99d6213b579a84c85ad37f2aa8ded4857c53c (patch) | |
tree | d05bb74c5ca30650ff0622cd1ffd2fd6ddecebd6 /mm/memcontrol.c | |
parent | 7ffd4ca7a2cdd7a18f0b499a4e9e0e7cf36ba018 (diff) |
memcg: unify charge/uncharge quantities to units of pages
There is no clear pattern when we pass a page count and when we pass a
byte count that is a multiple of PAGE_SIZE.
We never charge or uncharge subpage quantities, so convert it all to page
counts.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Cc: Balbir Singh <balbir@linux.vnet.ibm.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.c | 135 |
1 files changed, 65 insertions, 70 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 9dfbed2aacc9..bc02218eab01 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1109,16 +1109,16 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan, | |||
1109 | * @mem: the memory cgroup | 1109 | * @mem: the memory cgroup |
1110 | * | 1110 | * |
1111 | * Returns the maximum amount of memory @mem can be charged with, in | 1111 | * Returns the maximum amount of memory @mem can be charged with, in |
1112 | * bytes. | 1112 | * pages. |
1113 | */ | 1113 | */ |
1114 | static unsigned long long mem_cgroup_margin(struct mem_cgroup *mem) | 1114 | static unsigned long mem_cgroup_margin(struct mem_cgroup *mem) |
1115 | { | 1115 | { |
1116 | unsigned long long margin; | 1116 | unsigned long long margin; |
1117 | 1117 | ||
1118 | margin = res_counter_margin(&mem->res); | 1118 | margin = res_counter_margin(&mem->res); |
1119 | if (do_swap_account) | 1119 | if (do_swap_account) |
1120 | margin = min(margin, res_counter_margin(&mem->memsw)); | 1120 | margin = min(margin, res_counter_margin(&mem->memsw)); |
1121 | return margin; | 1121 | return margin >> PAGE_SHIFT; |
1122 | } | 1122 | } |
1123 | 1123 | ||
1124 | static unsigned int get_swappiness(struct mem_cgroup *memcg) | 1124 | static unsigned int get_swappiness(struct mem_cgroup *memcg) |
@@ -1647,7 +1647,7 @@ EXPORT_SYMBOL(mem_cgroup_update_page_stat); | |||
1647 | * size of first charge trial. "32" comes from vmscan.c's magic value. | 1647 | * size of first charge trial. "32" comes from vmscan.c's magic value. |
1648 | * TODO: maybe necessary to use big numbers in big irons. | 1648 | * TODO: maybe necessary to use big numbers in big irons. |
1649 | */ | 1649 | */ |
1650 | #define CHARGE_SIZE (32 * PAGE_SIZE) | 1650 | #define CHARGE_BATCH 32U |
1651 | struct memcg_stock_pcp { | 1651 | struct memcg_stock_pcp { |
1652 | struct mem_cgroup *cached; /* this never be root cgroup */ | 1652 | struct mem_cgroup *cached; /* this never be root cgroup */ |
1653 | unsigned int nr_pages; | 1653 | unsigned int nr_pages; |
@@ -1822,9 +1822,10 @@ enum { | |||
1822 | CHARGE_OOM_DIE, /* the current is killed because of OOM */ | 1822 | CHARGE_OOM_DIE, /* the current is killed because of OOM */ |
1823 | }; | 1823 | }; |
1824 | 1824 | ||
1825 | static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask, | 1825 | static int mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask, |
1826 | int csize, bool oom_check) | 1826 | unsigned int nr_pages, bool oom_check) |
1827 | { | 1827 | { |
1828 | unsigned long csize = nr_pages * PAGE_SIZE; | ||
1828 | struct mem_cgroup *mem_over_limit; | 1829 | struct mem_cgroup *mem_over_limit; |
1829 | struct res_counter *fail_res; | 1830 | struct res_counter *fail_res; |
1830 | unsigned long flags = 0; | 1831 | unsigned long flags = 0; |
@@ -1845,14 +1846,13 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask, | |||
1845 | } else | 1846 | } else |
1846 | mem_over_limit = mem_cgroup_from_res_counter(fail_res, res); | 1847 | mem_over_limit = mem_cgroup_from_res_counter(fail_res, res); |
1847 | /* | 1848 | /* |
1848 | * csize can be either a huge page (HPAGE_SIZE), a batch of | 1849 | * nr_pages can be either a huge page (HPAGE_PMD_NR), a batch |
1849 | * regular pages (CHARGE_SIZE), or a single regular page | 1850 | * of regular pages (CHARGE_BATCH), or a single regular page (1). |
1850 | * (PAGE_SIZE). | ||
1851 | * | 1851 | * |
1852 | * Never reclaim on behalf of optional batching, retry with a | 1852 | * Never reclaim on behalf of optional batching, retry with a |
1853 | * single page instead. | 1853 | * single page instead. |
1854 | */ | 1854 | */ |
1855 | if (csize == CHARGE_SIZE) | 1855 | if (nr_pages == CHARGE_BATCH) |
1856 | return CHARGE_RETRY; | 1856 | return CHARGE_RETRY; |
1857 | 1857 | ||
1858 | if (!(gfp_mask & __GFP_WAIT)) | 1858 | if (!(gfp_mask & __GFP_WAIT)) |
@@ -1860,7 +1860,7 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask, | |||
1860 | 1860 | ||
1861 | ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL, | 1861 | ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL, |
1862 | gfp_mask, flags); | 1862 | gfp_mask, flags); |
1863 | if (mem_cgroup_margin(mem_over_limit) >= csize) | 1863 | if (mem_cgroup_margin(mem_over_limit) >= nr_pages) |
1864 | return CHARGE_RETRY; | 1864 | return CHARGE_RETRY; |
1865 | /* | 1865 | /* |
1866 | * Even though the limit is exceeded at this point, reclaim | 1866 | * Even though the limit is exceeded at this point, reclaim |
@@ -1871,7 +1871,7 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask, | |||
1871 | * unlikely to succeed so close to the limit, and we fall back | 1871 | * unlikely to succeed so close to the limit, and we fall back |
1872 | * to regular pages anyway in case of failure. | 1872 | * to regular pages anyway in case of failure. |
1873 | */ | 1873 | */ |
1874 | if (csize == PAGE_SIZE && ret) | 1874 | if (nr_pages == 1 && ret) |
1875 | return CHARGE_RETRY; | 1875 | return CHARGE_RETRY; |
1876 | 1876 | ||
1877 | /* | 1877 | /* |
@@ -1897,13 +1897,14 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask, | |||
1897 | */ | 1897 | */ |
1898 | static int __mem_cgroup_try_charge(struct mm_struct *mm, | 1898 | static int __mem_cgroup_try_charge(struct mm_struct *mm, |
1899 | gfp_t gfp_mask, | 1899 | gfp_t gfp_mask, |
1900 | struct mem_cgroup **memcg, bool oom, | 1900 | unsigned int nr_pages, |
1901 | int page_size) | 1901 | struct mem_cgroup **memcg, |
1902 | bool oom) | ||
1902 | { | 1903 | { |
1904 | unsigned int batch = max(CHARGE_BATCH, nr_pages); | ||
1903 | int nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES; | 1905 | int nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES; |
1904 | struct mem_cgroup *mem = NULL; | 1906 | struct mem_cgroup *mem = NULL; |
1905 | int ret; | 1907 | int ret; |
1906 | int csize = max(CHARGE_SIZE, (unsigned long) page_size); | ||
1907 | 1908 | ||
1908 | /* | 1909 | /* |
1909 | * Unlike gloval-vm's OOM-kill, we're not in memory shortage | 1910 | * Unlike gloval-vm's OOM-kill, we're not in memory shortage |
@@ -1928,7 +1929,7 @@ again: | |||
1928 | VM_BUG_ON(css_is_removed(&mem->css)); | 1929 | VM_BUG_ON(css_is_removed(&mem->css)); |
1929 | if (mem_cgroup_is_root(mem)) | 1930 | if (mem_cgroup_is_root(mem)) |
1930 | goto done; | 1931 | goto done; |
1931 | if (page_size == PAGE_SIZE && consume_stock(mem)) | 1932 | if (nr_pages == 1 && consume_stock(mem)) |
1932 | goto done; | 1933 | goto done; |
1933 | css_get(&mem->css); | 1934 | css_get(&mem->css); |
1934 | } else { | 1935 | } else { |
@@ -1951,7 +1952,7 @@ again: | |||
1951 | rcu_read_unlock(); | 1952 | rcu_read_unlock(); |
1952 | goto done; | 1953 | goto done; |
1953 | } | 1954 | } |
1954 | if (page_size == PAGE_SIZE && consume_stock(mem)) { | 1955 | if (nr_pages == 1 && consume_stock(mem)) { |
1955 | /* | 1956 | /* |
1956 | * It seems dagerous to access memcg without css_get(). | 1957 | * It seems dagerous to access memcg without css_get(). |
1957 | * But considering how consume_stok works, it's not | 1958 | * But considering how consume_stok works, it's not |
@@ -1986,13 +1987,12 @@ again: | |||
1986 | nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES; | 1987 | nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES; |
1987 | } | 1988 | } |
1988 | 1989 | ||
1989 | ret = __mem_cgroup_do_charge(mem, gfp_mask, csize, oom_check); | 1990 | ret = mem_cgroup_do_charge(mem, gfp_mask, batch, oom_check); |
1990 | |||
1991 | switch (ret) { | 1991 | switch (ret) { |
1992 | case CHARGE_OK: | 1992 | case CHARGE_OK: |
1993 | break; | 1993 | break; |
1994 | case CHARGE_RETRY: /* not in OOM situation but retry */ | 1994 | case CHARGE_RETRY: /* not in OOM situation but retry */ |
1995 | csize = page_size; | 1995 | batch = nr_pages; |
1996 | css_put(&mem->css); | 1996 | css_put(&mem->css); |
1997 | mem = NULL; | 1997 | mem = NULL; |
1998 | goto again; | 1998 | goto again; |
@@ -2013,8 +2013,8 @@ again: | |||
2013 | } | 2013 | } |
2014 | } while (ret != CHARGE_OK); | 2014 | } while (ret != CHARGE_OK); |
2015 | 2015 | ||
2016 | if (csize > page_size) | 2016 | if (batch > nr_pages) |
2017 | refill_stock(mem, (csize - page_size) >> PAGE_SHIFT); | 2017 | refill_stock(mem, batch - nr_pages); |
2018 | css_put(&mem->css); | 2018 | css_put(&mem->css); |
2019 | done: | 2019 | done: |
2020 | *memcg = mem; | 2020 | *memcg = mem; |
@@ -2093,12 +2093,10 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page) | |||
2093 | 2093 | ||
2094 | static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, | 2094 | static void __mem_cgroup_commit_charge(struct mem_cgroup *mem, |
2095 | struct page *page, | 2095 | struct page *page, |
2096 | unsigned int nr_pages, | ||
2096 | struct page_cgroup *pc, | 2097 | struct page_cgroup *pc, |
2097 | enum charge_type ctype, | 2098 | enum charge_type ctype) |
2098 | int page_size) | ||
2099 | { | 2099 | { |
2100 | int nr_pages = page_size >> PAGE_SHIFT; | ||
2101 | |||
2102 | lock_page_cgroup(pc); | 2100 | lock_page_cgroup(pc); |
2103 | if (unlikely(PageCgroupUsed(pc))) { | 2101 | if (unlikely(PageCgroupUsed(pc))) { |
2104 | unlock_page_cgroup(pc); | 2102 | unlock_page_cgroup(pc); |
@@ -2187,26 +2185,28 @@ void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail) | |||
2187 | /** | 2185 | /** |
2188 | * mem_cgroup_move_account - move account of the page | 2186 | * mem_cgroup_move_account - move account of the page |
2189 | * @page: the page | 2187 | * @page: the page |
2188 | * @nr_pages: number of regular pages (>1 for huge pages) | ||
2190 | * @pc: page_cgroup of the page. | 2189 | * @pc: page_cgroup of the page. |
2191 | * @from: mem_cgroup which the page is moved from. | 2190 | * @from: mem_cgroup which the page is moved from. |
2192 | * @to: mem_cgroup which the page is moved to. @from != @to. | 2191 | * @to: mem_cgroup which the page is moved to. @from != @to. |
2193 | * @uncharge: whether we should call uncharge and css_put against @from. | 2192 | * @uncharge: whether we should call uncharge and css_put against @from. |
2194 | * @charge_size: number of bytes to charge (regular or huge page) | ||
2195 | * | 2193 | * |
2196 | * The caller must confirm following. | 2194 | * The caller must confirm following. |
2197 | * - page is not on LRU (isolate_page() is useful.) | 2195 | * - page is not on LRU (isolate_page() is useful.) |
2198 | * - compound_lock is held when charge_size > PAGE_SIZE | 2196 | * - compound_lock is held when nr_pages > 1 |
2199 | * | 2197 | * |
2200 | * This function doesn't do "charge" nor css_get to new cgroup. It should be | 2198 | * This function doesn't do "charge" nor css_get to new cgroup. It should be |
2201 | * done by a caller(__mem_cgroup_try_charge would be usefull). If @uncharge is | 2199 | * done by a caller(__mem_cgroup_try_charge would be usefull). If @uncharge is |
2202 | * true, this function does "uncharge" from old cgroup, but it doesn't if | 2200 | * true, this function does "uncharge" from old cgroup, but it doesn't if |
2203 | * @uncharge is false, so a caller should do "uncharge". | 2201 | * @uncharge is false, so a caller should do "uncharge". |
2204 | */ | 2202 | */ |
2205 | static int mem_cgroup_move_account(struct page *page, struct page_cgroup *pc, | 2203 | static int mem_cgroup_move_account(struct page *page, |
2206 | struct mem_cgroup *from, struct mem_cgroup *to, | 2204 | unsigned int nr_pages, |
2207 | bool uncharge, int charge_size) | 2205 | struct page_cgroup *pc, |
2206 | struct mem_cgroup *from, | ||
2207 | struct mem_cgroup *to, | ||
2208 | bool uncharge) | ||
2208 | { | 2209 | { |
2209 | int nr_pages = charge_size >> PAGE_SHIFT; | ||
2210 | unsigned long flags; | 2210 | unsigned long flags; |
2211 | int ret; | 2211 | int ret; |
2212 | 2212 | ||
@@ -2219,7 +2219,7 @@ static int mem_cgroup_move_account(struct page *page, struct page_cgroup *pc, | |||
2219 | * hold it. | 2219 | * hold it. |
2220 | */ | 2220 | */ |
2221 | ret = -EBUSY; | 2221 | ret = -EBUSY; |
2222 | if (charge_size > PAGE_SIZE && !PageTransHuge(page)) | 2222 | if (nr_pages > 1 && !PageTransHuge(page)) |
2223 | goto out; | 2223 | goto out; |
2224 | 2224 | ||
2225 | lock_page_cgroup(pc); | 2225 | lock_page_cgroup(pc); |
@@ -2277,7 +2277,7 @@ static int mem_cgroup_move_parent(struct page *page, | |||
2277 | struct cgroup *cg = child->css.cgroup; | 2277 | struct cgroup *cg = child->css.cgroup; |
2278 | struct cgroup *pcg = cg->parent; | 2278 | struct cgroup *pcg = cg->parent; |
2279 | struct mem_cgroup *parent; | 2279 | struct mem_cgroup *parent; |
2280 | int page_size = PAGE_SIZE; | 2280 | unsigned int nr_pages; |
2281 | unsigned long flags; | 2281 | unsigned long flags; |
2282 | int ret; | 2282 | int ret; |
2283 | 2283 | ||
@@ -2291,23 +2291,21 @@ static int mem_cgroup_move_parent(struct page *page, | |||
2291 | if (isolate_lru_page(page)) | 2291 | if (isolate_lru_page(page)) |
2292 | goto put; | 2292 | goto put; |
2293 | 2293 | ||
2294 | if (PageTransHuge(page)) | 2294 | nr_pages = hpage_nr_pages(page); |
2295 | page_size = HPAGE_SIZE; | ||
2296 | 2295 | ||
2297 | parent = mem_cgroup_from_cont(pcg); | 2296 | parent = mem_cgroup_from_cont(pcg); |
2298 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, | 2297 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, nr_pages, &parent, false); |
2299 | &parent, false, page_size); | ||
2300 | if (ret || !parent) | 2298 | if (ret || !parent) |
2301 | goto put_back; | 2299 | goto put_back; |
2302 | 2300 | ||
2303 | if (page_size > PAGE_SIZE) | 2301 | if (nr_pages > 1) |
2304 | flags = compound_lock_irqsave(page); | 2302 | flags = compound_lock_irqsave(page); |
2305 | 2303 | ||
2306 | ret = mem_cgroup_move_account(page, pc, child, parent, true, page_size); | 2304 | ret = mem_cgroup_move_account(page, nr_pages, pc, child, parent, true); |
2307 | if (ret) | 2305 | if (ret) |
2308 | __mem_cgroup_cancel_charge(parent, page_size >> PAGE_SHIFT); | 2306 | __mem_cgroup_cancel_charge(parent, nr_pages); |
2309 | 2307 | ||
2310 | if (page_size > PAGE_SIZE) | 2308 | if (nr_pages > 1) |
2311 | compound_unlock_irqrestore(page, flags); | 2309 | compound_unlock_irqrestore(page, flags); |
2312 | put_back: | 2310 | put_back: |
2313 | putback_lru_page(page); | 2311 | putback_lru_page(page); |
@@ -2327,13 +2325,13 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm, | |||
2327 | gfp_t gfp_mask, enum charge_type ctype) | 2325 | gfp_t gfp_mask, enum charge_type ctype) |
2328 | { | 2326 | { |
2329 | struct mem_cgroup *mem = NULL; | 2327 | struct mem_cgroup *mem = NULL; |
2330 | int page_size = PAGE_SIZE; | 2328 | unsigned int nr_pages = 1; |
2331 | struct page_cgroup *pc; | 2329 | struct page_cgroup *pc; |
2332 | bool oom = true; | 2330 | bool oom = true; |
2333 | int ret; | 2331 | int ret; |
2334 | 2332 | ||
2335 | if (PageTransHuge(page)) { | 2333 | if (PageTransHuge(page)) { |
2336 | page_size <<= compound_order(page); | 2334 | nr_pages <<= compound_order(page); |
2337 | VM_BUG_ON(!PageTransHuge(page)); | 2335 | VM_BUG_ON(!PageTransHuge(page)); |
2338 | /* | 2336 | /* |
2339 | * Never OOM-kill a process for a huge page. The | 2337 | * Never OOM-kill a process for a huge page. The |
@@ -2345,11 +2343,11 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm, | |||
2345 | pc = lookup_page_cgroup(page); | 2343 | pc = lookup_page_cgroup(page); |
2346 | BUG_ON(!pc); /* XXX: remove this and move pc lookup into commit */ | 2344 | BUG_ON(!pc); /* XXX: remove this and move pc lookup into commit */ |
2347 | 2345 | ||
2348 | ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, oom, page_size); | 2346 | ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &mem, oom); |
2349 | if (ret || !mem) | 2347 | if (ret || !mem) |
2350 | return ret; | 2348 | return ret; |
2351 | 2349 | ||
2352 | __mem_cgroup_commit_charge(mem, page, pc, ctype, page_size); | 2350 | __mem_cgroup_commit_charge(mem, page, nr_pages, pc, ctype); |
2353 | return 0; | 2351 | return 0; |
2354 | } | 2352 | } |
2355 | 2353 | ||
@@ -2465,13 +2463,13 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm, | |||
2465 | if (!mem) | 2463 | if (!mem) |
2466 | goto charge_cur_mm; | 2464 | goto charge_cur_mm; |
2467 | *ptr = mem; | 2465 | *ptr = mem; |
2468 | ret = __mem_cgroup_try_charge(NULL, mask, ptr, true, PAGE_SIZE); | 2466 | ret = __mem_cgroup_try_charge(NULL, mask, 1, ptr, true); |
2469 | css_put(&mem->css); | 2467 | css_put(&mem->css); |
2470 | return ret; | 2468 | return ret; |
2471 | charge_cur_mm: | 2469 | charge_cur_mm: |
2472 | if (unlikely(!mm)) | 2470 | if (unlikely(!mm)) |
2473 | mm = &init_mm; | 2471 | mm = &init_mm; |
2474 | return __mem_cgroup_try_charge(mm, mask, ptr, true, PAGE_SIZE); | 2472 | return __mem_cgroup_try_charge(mm, mask, 1, ptr, true); |
2475 | } | 2473 | } |
2476 | 2474 | ||
2477 | static void | 2475 | static void |
@@ -2487,7 +2485,7 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr, | |||
2487 | cgroup_exclude_rmdir(&ptr->css); | 2485 | cgroup_exclude_rmdir(&ptr->css); |
2488 | pc = lookup_page_cgroup(page); | 2486 | pc = lookup_page_cgroup(page); |
2489 | mem_cgroup_lru_del_before_commit_swapcache(page); | 2487 | mem_cgroup_lru_del_before_commit_swapcache(page); |
2490 | __mem_cgroup_commit_charge(ptr, page, pc, ctype, PAGE_SIZE); | 2488 | __mem_cgroup_commit_charge(ptr, page, 1, pc, ctype); |
2491 | mem_cgroup_lru_add_after_commit_swapcache(page); | 2489 | mem_cgroup_lru_add_after_commit_swapcache(page); |
2492 | /* | 2490 | /* |
2493 | * Now swap is on-memory. This means this page may be | 2491 | * Now swap is on-memory. This means this page may be |
@@ -2539,12 +2537,13 @@ void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *mem) | |||
2539 | __mem_cgroup_cancel_charge(mem, 1); | 2537 | __mem_cgroup_cancel_charge(mem, 1); |
2540 | } | 2538 | } |
2541 | 2539 | ||
2542 | static void | 2540 | static void mem_cgroup_do_uncharge(struct mem_cgroup *mem, |
2543 | __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype, | 2541 | unsigned int nr_pages, |
2544 | int page_size) | 2542 | const enum charge_type ctype) |
2545 | { | 2543 | { |
2546 | struct memcg_batch_info *batch = NULL; | 2544 | struct memcg_batch_info *batch = NULL; |
2547 | bool uncharge_memsw = true; | 2545 | bool uncharge_memsw = true; |
2546 | |||
2548 | /* If swapout, usage of swap doesn't decrease */ | 2547 | /* If swapout, usage of swap doesn't decrease */ |
2549 | if (!do_swap_account || ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT) | 2548 | if (!do_swap_account || ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT) |
2550 | uncharge_memsw = false; | 2549 | uncharge_memsw = false; |
@@ -2568,7 +2567,7 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype, | |||
2568 | if (!batch->do_batch || test_thread_flag(TIF_MEMDIE)) | 2567 | if (!batch->do_batch || test_thread_flag(TIF_MEMDIE)) |
2569 | goto direct_uncharge; | 2568 | goto direct_uncharge; |
2570 | 2569 | ||
2571 | if (page_size != PAGE_SIZE) | 2570 | if (nr_pages > 1) |
2572 | goto direct_uncharge; | 2571 | goto direct_uncharge; |
2573 | 2572 | ||
2574 | /* | 2573 | /* |
@@ -2584,9 +2583,9 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype, | |||
2584 | batch->memsw_nr_pages++; | 2583 | batch->memsw_nr_pages++; |
2585 | return; | 2584 | return; |
2586 | direct_uncharge: | 2585 | direct_uncharge: |
2587 | res_counter_uncharge(&mem->res, page_size); | 2586 | res_counter_uncharge(&mem->res, nr_pages * PAGE_SIZE); |
2588 | if (uncharge_memsw) | 2587 | if (uncharge_memsw) |
2589 | res_counter_uncharge(&mem->memsw, page_size); | 2588 | res_counter_uncharge(&mem->memsw, nr_pages * PAGE_SIZE); |
2590 | if (unlikely(batch->memcg != mem)) | 2589 | if (unlikely(batch->memcg != mem)) |
2591 | memcg_oom_recover(mem); | 2590 | memcg_oom_recover(mem); |
2592 | return; | 2591 | return; |
@@ -2598,10 +2597,9 @@ direct_uncharge: | |||
2598 | static struct mem_cgroup * | 2597 | static struct mem_cgroup * |
2599 | __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) | 2598 | __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) |
2600 | { | 2599 | { |
2601 | int count; | ||
2602 | struct page_cgroup *pc; | ||
2603 | struct mem_cgroup *mem = NULL; | 2600 | struct mem_cgroup *mem = NULL; |
2604 | int page_size = PAGE_SIZE; | 2601 | unsigned int nr_pages = 1; |
2602 | struct page_cgroup *pc; | ||
2605 | 2603 | ||
2606 | if (mem_cgroup_disabled()) | 2604 | if (mem_cgroup_disabled()) |
2607 | return NULL; | 2605 | return NULL; |
@@ -2610,11 +2608,9 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) | |||
2610 | return NULL; | 2608 | return NULL; |
2611 | 2609 | ||
2612 | if (PageTransHuge(page)) { | 2610 | if (PageTransHuge(page)) { |
2613 | page_size <<= compound_order(page); | 2611 | nr_pages <<= compound_order(page); |
2614 | VM_BUG_ON(!PageTransHuge(page)); | 2612 | VM_BUG_ON(!PageTransHuge(page)); |
2615 | } | 2613 | } |
2616 | |||
2617 | count = page_size >> PAGE_SHIFT; | ||
2618 | /* | 2614 | /* |
2619 | * Check if our page_cgroup is valid | 2615 | * Check if our page_cgroup is valid |
2620 | */ | 2616 | */ |
@@ -2647,7 +2643,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) | |||
2647 | break; | 2643 | break; |
2648 | } | 2644 | } |
2649 | 2645 | ||
2650 | mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -count); | 2646 | mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -nr_pages); |
2651 | 2647 | ||
2652 | ClearPageCgroupUsed(pc); | 2648 | ClearPageCgroupUsed(pc); |
2653 | /* | 2649 | /* |
@@ -2668,7 +2664,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype) | |||
2668 | mem_cgroup_get(mem); | 2664 | mem_cgroup_get(mem); |
2669 | } | 2665 | } |
2670 | if (!mem_cgroup_is_root(mem)) | 2666 | if (!mem_cgroup_is_root(mem)) |
2671 | __do_uncharge(mem, ctype, page_size); | 2667 | mem_cgroup_do_uncharge(mem, nr_pages, ctype); |
2672 | 2668 | ||
2673 | return mem; | 2669 | return mem; |
2674 | 2670 | ||
@@ -2860,8 +2856,8 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry, | |||
2860 | int mem_cgroup_prepare_migration(struct page *page, | 2856 | int mem_cgroup_prepare_migration(struct page *page, |
2861 | struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask) | 2857 | struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask) |
2862 | { | 2858 | { |
2863 | struct page_cgroup *pc; | ||
2864 | struct mem_cgroup *mem = NULL; | 2859 | struct mem_cgroup *mem = NULL; |
2860 | struct page_cgroup *pc; | ||
2865 | enum charge_type ctype; | 2861 | enum charge_type ctype; |
2866 | int ret = 0; | 2862 | int ret = 0; |
2867 | 2863 | ||
@@ -2917,7 +2913,7 @@ int mem_cgroup_prepare_migration(struct page *page, | |||
2917 | return 0; | 2913 | return 0; |
2918 | 2914 | ||
2919 | *ptr = mem; | 2915 | *ptr = mem; |
2920 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, ptr, false, PAGE_SIZE); | 2916 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, 1, ptr, false); |
2921 | css_put(&mem->css);/* drop extra refcnt */ | 2917 | css_put(&mem->css);/* drop extra refcnt */ |
2922 | if (ret || *ptr == NULL) { | 2918 | if (ret || *ptr == NULL) { |
2923 | if (PageAnon(page)) { | 2919 | if (PageAnon(page)) { |
@@ -2944,7 +2940,7 @@ int mem_cgroup_prepare_migration(struct page *page, | |||
2944 | ctype = MEM_CGROUP_CHARGE_TYPE_CACHE; | 2940 | ctype = MEM_CGROUP_CHARGE_TYPE_CACHE; |
2945 | else | 2941 | else |
2946 | ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM; | 2942 | ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM; |
2947 | __mem_cgroup_commit_charge(mem, page, pc, ctype, PAGE_SIZE); | 2943 | __mem_cgroup_commit_charge(mem, page, 1, pc, ctype); |
2948 | return ret; | 2944 | return ret; |
2949 | } | 2945 | } |
2950 | 2946 | ||
@@ -4598,8 +4594,7 @@ one_by_one: | |||
4598 | batch_count = PRECHARGE_COUNT_AT_ONCE; | 4594 | batch_count = PRECHARGE_COUNT_AT_ONCE; |
4599 | cond_resched(); | 4595 | cond_resched(); |
4600 | } | 4596 | } |
4601 | ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, &mem, false, | 4597 | ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, 1, &mem, false); |
4602 | PAGE_SIZE); | ||
4603 | if (ret || !mem) | 4598 | if (ret || !mem) |
4604 | /* mem_cgroup_clear_mc() will do uncharge later */ | 4599 | /* mem_cgroup_clear_mc() will do uncharge later */ |
4605 | return -ENOMEM; | 4600 | return -ENOMEM; |
@@ -4945,8 +4940,8 @@ retry: | |||
4945 | if (isolate_lru_page(page)) | 4940 | if (isolate_lru_page(page)) |
4946 | goto put; | 4941 | goto put; |
4947 | pc = lookup_page_cgroup(page); | 4942 | pc = lookup_page_cgroup(page); |
4948 | if (!mem_cgroup_move_account(page, pc, | 4943 | if (!mem_cgroup_move_account(page, 1, pc, |
4949 | mc.from, mc.to, false, PAGE_SIZE)) { | 4944 | mc.from, mc.to, false)) { |
4950 | mc.precharge--; | 4945 | mc.precharge--; |
4951 | /* we uncharge from mc.from later. */ | 4946 | /* we uncharge from mc.from later. */ |
4952 | mc.moved_charge++; | 4947 | mc.moved_charge++; |