diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memcontrol.c | 264 |
1 files changed, 125 insertions, 139 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ebf1139f323e..c7a9cb627180 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -72,22 +72,13 @@ EXPORT_SYMBOL(memory_cgrp_subsys); | |||
72 | #define MEM_CGROUP_RECLAIM_RETRIES 5 | 72 | #define MEM_CGROUP_RECLAIM_RETRIES 5 |
73 | static struct mem_cgroup *root_mem_cgroup __read_mostly; | 73 | static struct mem_cgroup *root_mem_cgroup __read_mostly; |
74 | 74 | ||
75 | /* Whether the swap controller is active */ | ||
75 | #ifdef CONFIG_MEMCG_SWAP | 76 | #ifdef CONFIG_MEMCG_SWAP |
76 | /* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */ | ||
77 | int do_swap_account __read_mostly; | 77 | int do_swap_account __read_mostly; |
78 | |||
79 | /* for remember boot option*/ | ||
80 | #ifdef CONFIG_MEMCG_SWAP_ENABLED | ||
81 | static int really_do_swap_account __initdata = 1; | ||
82 | #else | ||
83 | static int really_do_swap_account __initdata; | ||
84 | #endif | ||
85 | |||
86 | #else | 78 | #else |
87 | #define do_swap_account 0 | 79 | #define do_swap_account 0 |
88 | #endif | 80 | #endif |
89 | 81 | ||
90 | |||
91 | static const char * const mem_cgroup_stat_names[] = { | 82 | static const char * const mem_cgroup_stat_names[] = { |
92 | "cache", | 83 | "cache", |
93 | "rss", | 84 | "rss", |
@@ -4373,34 +4364,6 @@ static struct cftype mem_cgroup_legacy_files[] = { | |||
4373 | { }, /* terminate */ | 4364 | { }, /* terminate */ |
4374 | }; | 4365 | }; |
4375 | 4366 | ||
4376 | #ifdef CONFIG_MEMCG_SWAP | ||
4377 | static struct cftype memsw_cgroup_files[] = { | ||
4378 | { | ||
4379 | .name = "memsw.usage_in_bytes", | ||
4380 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), | ||
4381 | .read_u64 = mem_cgroup_read_u64, | ||
4382 | }, | ||
4383 | { | ||
4384 | .name = "memsw.max_usage_in_bytes", | ||
4385 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE), | ||
4386 | .write = mem_cgroup_reset, | ||
4387 | .read_u64 = mem_cgroup_read_u64, | ||
4388 | }, | ||
4389 | { | ||
4390 | .name = "memsw.limit_in_bytes", | ||
4391 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT), | ||
4392 | .write = mem_cgroup_write, | ||
4393 | .read_u64 = mem_cgroup_read_u64, | ||
4394 | }, | ||
4395 | { | ||
4396 | .name = "memsw.failcnt", | ||
4397 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT), | ||
4398 | .write = mem_cgroup_reset, | ||
4399 | .read_u64 = mem_cgroup_read_u64, | ||
4400 | }, | ||
4401 | { }, /* terminate */ | ||
4402 | }; | ||
4403 | #endif | ||
4404 | static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) | 4367 | static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) |
4405 | { | 4368 | { |
4406 | struct mem_cgroup_per_node *pn; | 4369 | struct mem_cgroup_per_node *pn; |
@@ -5391,37 +5354,6 @@ struct cgroup_subsys memory_cgrp_subsys = { | |||
5391 | .early_init = 0, | 5354 | .early_init = 0, |
5392 | }; | 5355 | }; |
5393 | 5356 | ||
5394 | #ifdef CONFIG_MEMCG_SWAP | ||
5395 | static int __init enable_swap_account(char *s) | ||
5396 | { | ||
5397 | if (!strcmp(s, "1")) | ||
5398 | really_do_swap_account = 1; | ||
5399 | else if (!strcmp(s, "0")) | ||
5400 | really_do_swap_account = 0; | ||
5401 | return 1; | ||
5402 | } | ||
5403 | __setup("swapaccount=", enable_swap_account); | ||
5404 | |||
5405 | static void __init memsw_file_init(void) | ||
5406 | { | ||
5407 | WARN_ON(cgroup_add_legacy_cftypes(&memory_cgrp_subsys, | ||
5408 | memsw_cgroup_files)); | ||
5409 | } | ||
5410 | |||
5411 | static void __init enable_swap_cgroup(void) | ||
5412 | { | ||
5413 | if (!mem_cgroup_disabled() && really_do_swap_account) { | ||
5414 | do_swap_account = 1; | ||
5415 | memsw_file_init(); | ||
5416 | } | ||
5417 | } | ||
5418 | |||
5419 | #else | ||
5420 | static void __init enable_swap_cgroup(void) | ||
5421 | { | ||
5422 | } | ||
5423 | #endif | ||
5424 | |||
5425 | /** | 5357 | /** |
5426 | * mem_cgroup_events - count memory events against a cgroup | 5358 | * mem_cgroup_events - count memory events against a cgroup |
5427 | * @memcg: the memory cgroup | 5359 | * @memcg: the memory cgroup |
@@ -5472,74 +5404,6 @@ bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg) | |||
5472 | return true; | 5404 | return true; |
5473 | } | 5405 | } |
5474 | 5406 | ||
5475 | #ifdef CONFIG_MEMCG_SWAP | ||
5476 | /** | ||
5477 | * mem_cgroup_swapout - transfer a memsw charge to swap | ||
5478 | * @page: page whose memsw charge to transfer | ||
5479 | * @entry: swap entry to move the charge to | ||
5480 | * | ||
5481 | * Transfer the memsw charge of @page to @entry. | ||
5482 | */ | ||
5483 | void mem_cgroup_swapout(struct page *page, swp_entry_t entry) | ||
5484 | { | ||
5485 | struct mem_cgroup *memcg; | ||
5486 | unsigned short oldid; | ||
5487 | |||
5488 | VM_BUG_ON_PAGE(PageLRU(page), page); | ||
5489 | VM_BUG_ON_PAGE(page_count(page), page); | ||
5490 | |||
5491 | if (!do_swap_account) | ||
5492 | return; | ||
5493 | |||
5494 | memcg = page->mem_cgroup; | ||
5495 | |||
5496 | /* Readahead page, never charged */ | ||
5497 | if (!memcg) | ||
5498 | return; | ||
5499 | |||
5500 | oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); | ||
5501 | VM_BUG_ON_PAGE(oldid, page); | ||
5502 | mem_cgroup_swap_statistics(memcg, true); | ||
5503 | |||
5504 | page->mem_cgroup = NULL; | ||
5505 | |||
5506 | if (!mem_cgroup_is_root(memcg)) | ||
5507 | page_counter_uncharge(&memcg->memory, 1); | ||
5508 | |||
5509 | /* XXX: caller holds IRQ-safe mapping->tree_lock */ | ||
5510 | VM_BUG_ON(!irqs_disabled()); | ||
5511 | |||
5512 | mem_cgroup_charge_statistics(memcg, page, -1); | ||
5513 | memcg_check_events(memcg, page); | ||
5514 | } | ||
5515 | |||
5516 | /** | ||
5517 | * mem_cgroup_uncharge_swap - uncharge a swap entry | ||
5518 | * @entry: swap entry to uncharge | ||
5519 | * | ||
5520 | * Drop the memsw charge associated with @entry. | ||
5521 | */ | ||
5522 | void mem_cgroup_uncharge_swap(swp_entry_t entry) | ||
5523 | { | ||
5524 | struct mem_cgroup *memcg; | ||
5525 | unsigned short id; | ||
5526 | |||
5527 | if (!do_swap_account) | ||
5528 | return; | ||
5529 | |||
5530 | id = swap_cgroup_record(entry, 0); | ||
5531 | rcu_read_lock(); | ||
5532 | memcg = mem_cgroup_lookup(id); | ||
5533 | if (memcg) { | ||
5534 | if (!mem_cgroup_is_root(memcg)) | ||
5535 | page_counter_uncharge(&memcg->memsw, 1); | ||
5536 | mem_cgroup_swap_statistics(memcg, false); | ||
5537 | css_put(&memcg->css); | ||
5538 | } | ||
5539 | rcu_read_unlock(); | ||
5540 | } | ||
5541 | #endif | ||
5542 | |||
5543 | /** | 5407 | /** |
5544 | * mem_cgroup_try_charge - try charging a page | 5408 | * mem_cgroup_try_charge - try charging a page |
5545 | * @page: page to charge | 5409 | * @page: page to charge |
@@ -5897,8 +5761,130 @@ static int __init mem_cgroup_init(void) | |||
5897 | soft_limit_tree.rb_tree_per_node[node] = rtpn; | 5761 | soft_limit_tree.rb_tree_per_node[node] = rtpn; |
5898 | } | 5762 | } |
5899 | 5763 | ||
5900 | enable_swap_cgroup(); | ||
5901 | |||
5902 | return 0; | 5764 | return 0; |
5903 | } | 5765 | } |
5904 | subsys_initcall(mem_cgroup_init); | 5766 | subsys_initcall(mem_cgroup_init); |
5767 | |||
5768 | #ifdef CONFIG_MEMCG_SWAP | ||
5769 | /** | ||
5770 | * mem_cgroup_swapout - transfer a memsw charge to swap | ||
5771 | * @page: page whose memsw charge to transfer | ||
5772 | * @entry: swap entry to move the charge to | ||
5773 | * | ||
5774 | * Transfer the memsw charge of @page to @entry. | ||
5775 | */ | ||
5776 | void mem_cgroup_swapout(struct page *page, swp_entry_t entry) | ||
5777 | { | ||
5778 | struct mem_cgroup *memcg; | ||
5779 | unsigned short oldid; | ||
5780 | |||
5781 | VM_BUG_ON_PAGE(PageLRU(page), page); | ||
5782 | VM_BUG_ON_PAGE(page_count(page), page); | ||
5783 | |||
5784 | if (!do_swap_account) | ||
5785 | return; | ||
5786 | |||
5787 | memcg = page->mem_cgroup; | ||
5788 | |||
5789 | /* Readahead page, never charged */ | ||
5790 | if (!memcg) | ||
5791 | return; | ||
5792 | |||
5793 | oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); | ||
5794 | VM_BUG_ON_PAGE(oldid, page); | ||
5795 | mem_cgroup_swap_statistics(memcg, true); | ||
5796 | |||
5797 | page->mem_cgroup = NULL; | ||
5798 | |||
5799 | if (!mem_cgroup_is_root(memcg)) | ||
5800 | page_counter_uncharge(&memcg->memory, 1); | ||
5801 | |||
5802 | /* XXX: caller holds IRQ-safe mapping->tree_lock */ | ||
5803 | VM_BUG_ON(!irqs_disabled()); | ||
5804 | |||
5805 | mem_cgroup_charge_statistics(memcg, page, -1); | ||
5806 | memcg_check_events(memcg, page); | ||
5807 | } | ||
5808 | |||
5809 | /** | ||
5810 | * mem_cgroup_uncharge_swap - uncharge a swap entry | ||
5811 | * @entry: swap entry to uncharge | ||
5812 | * | ||
5813 | * Drop the memsw charge associated with @entry. | ||
5814 | */ | ||
5815 | void mem_cgroup_uncharge_swap(swp_entry_t entry) | ||
5816 | { | ||
5817 | struct mem_cgroup *memcg; | ||
5818 | unsigned short id; | ||
5819 | |||
5820 | if (!do_swap_account) | ||
5821 | return; | ||
5822 | |||
5823 | id = swap_cgroup_record(entry, 0); | ||
5824 | rcu_read_lock(); | ||
5825 | memcg = mem_cgroup_lookup(id); | ||
5826 | if (memcg) { | ||
5827 | if (!mem_cgroup_is_root(memcg)) | ||
5828 | page_counter_uncharge(&memcg->memsw, 1); | ||
5829 | mem_cgroup_swap_statistics(memcg, false); | ||
5830 | css_put(&memcg->css); | ||
5831 | } | ||
5832 | rcu_read_unlock(); | ||
5833 | } | ||
5834 | |||
5835 | /* for remember boot option*/ | ||
5836 | #ifdef CONFIG_MEMCG_SWAP_ENABLED | ||
5837 | static int really_do_swap_account __initdata = 1; | ||
5838 | #else | ||
5839 | static int really_do_swap_account __initdata; | ||
5840 | #endif | ||
5841 | |||
5842 | static int __init enable_swap_account(char *s) | ||
5843 | { | ||
5844 | if (!strcmp(s, "1")) | ||
5845 | really_do_swap_account = 1; | ||
5846 | else if (!strcmp(s, "0")) | ||
5847 | really_do_swap_account = 0; | ||
5848 | return 1; | ||
5849 | } | ||
5850 | __setup("swapaccount=", enable_swap_account); | ||
5851 | |||
5852 | static struct cftype memsw_cgroup_files[] = { | ||
5853 | { | ||
5854 | .name = "memsw.usage_in_bytes", | ||
5855 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), | ||
5856 | .read_u64 = mem_cgroup_read_u64, | ||
5857 | }, | ||
5858 | { | ||
5859 | .name = "memsw.max_usage_in_bytes", | ||
5860 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE), | ||
5861 | .write = mem_cgroup_reset, | ||
5862 | .read_u64 = mem_cgroup_read_u64, | ||
5863 | }, | ||
5864 | { | ||
5865 | .name = "memsw.limit_in_bytes", | ||
5866 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT), | ||
5867 | .write = mem_cgroup_write, | ||
5868 | .read_u64 = mem_cgroup_read_u64, | ||
5869 | }, | ||
5870 | { | ||
5871 | .name = "memsw.failcnt", | ||
5872 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT), | ||
5873 | .write = mem_cgroup_reset, | ||
5874 | .read_u64 = mem_cgroup_read_u64, | ||
5875 | }, | ||
5876 | { }, /* terminate */ | ||
5877 | }; | ||
5878 | |||
5879 | static int __init mem_cgroup_swap_init(void) | ||
5880 | { | ||
5881 | if (!mem_cgroup_disabled() && really_do_swap_account) { | ||
5882 | do_swap_account = 1; | ||
5883 | WARN_ON(cgroup_add_legacy_cftypes(&memory_cgrp_subsys, | ||
5884 | memsw_cgroup_files)); | ||
5885 | } | ||
5886 | return 0; | ||
5887 | } | ||
5888 | subsys_initcall(mem_cgroup_swap_init); | ||
5889 | |||
5890 | #endif /* CONFIG_MEMCG_SWAP */ | ||