aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c68
1 files changed, 56 insertions, 12 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index e74d7080ec9e..9a6a51a7c416 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4077,14 +4077,14 @@ static struct cftype mem_cgroup_legacy_files[] = {
4077 4077
4078static DEFINE_IDR(mem_cgroup_idr); 4078static DEFINE_IDR(mem_cgroup_idr);
4079 4079
4080static void mem_cgroup_id_get(struct mem_cgroup *memcg) 4080static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n)
4081{ 4081{
4082 atomic_inc(&memcg->id.ref); 4082 atomic_add(n, &memcg->id.ref);
4083} 4083}
4084 4084
4085static void mem_cgroup_id_put(struct mem_cgroup *memcg) 4085static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n)
4086{ 4086{
4087 if (atomic_dec_and_test(&memcg->id.ref)) { 4087 if (atomic_sub_and_test(n, &memcg->id.ref)) {
4088 idr_remove(&mem_cgroup_idr, memcg->id.id); 4088 idr_remove(&mem_cgroup_idr, memcg->id.id);
4089 memcg->id.id = 0; 4089 memcg->id.id = 0;
4090 4090
@@ -4093,6 +4093,16 @@ static void mem_cgroup_id_put(struct mem_cgroup *memcg)
4093 } 4093 }
4094} 4094}
4095 4095
4096static inline void mem_cgroup_id_get(struct mem_cgroup *memcg)
4097{
4098 mem_cgroup_id_get_many(memcg, 1);
4099}
4100
4101static inline void mem_cgroup_id_put(struct mem_cgroup *memcg)
4102{
4103 mem_cgroup_id_put_many(memcg, 1);
4104}
4105
4096/** 4106/**
4097 * mem_cgroup_from_id - look up a memcg from a memcg id 4107 * mem_cgroup_from_id - look up a memcg from a memcg id
4098 * @id: the memcg id to look up 4108 * @id: the memcg id to look up
@@ -4727,6 +4737,8 @@ static void __mem_cgroup_clear_mc(void)
4727 if (!mem_cgroup_is_root(mc.from)) 4737 if (!mem_cgroup_is_root(mc.from))
4728 page_counter_uncharge(&mc.from->memsw, mc.moved_swap); 4738 page_counter_uncharge(&mc.from->memsw, mc.moved_swap);
4729 4739
4740 mem_cgroup_id_put_many(mc.from, mc.moved_swap);
4741
4730 /* 4742 /*
4731 * we charged both to->memory and to->memsw, so we 4743 * we charged both to->memory and to->memsw, so we
4732 * should uncharge to->memory. 4744 * should uncharge to->memory.
@@ -4734,9 +4746,9 @@ static void __mem_cgroup_clear_mc(void)
4734 if (!mem_cgroup_is_root(mc.to)) 4746 if (!mem_cgroup_is_root(mc.to))
4735 page_counter_uncharge(&mc.to->memory, mc.moved_swap); 4747 page_counter_uncharge(&mc.to->memory, mc.moved_swap);
4736 4748
4737 css_put_many(&mc.from->css, mc.moved_swap); 4749 mem_cgroup_id_get_many(mc.to, mc.moved_swap);
4750 css_put_many(&mc.to->css, mc.moved_swap);
4738 4751
4739 /* we've already done css_get(mc.to) */
4740 mc.moved_swap = 0; 4752 mc.moved_swap = 0;
4741 } 4753 }
4742 memcg_oom_recover(from); 4754 memcg_oom_recover(from);
@@ -5791,6 +5803,24 @@ static int __init mem_cgroup_init(void)
5791subsys_initcall(mem_cgroup_init); 5803subsys_initcall(mem_cgroup_init);
5792 5804
5793#ifdef CONFIG_MEMCG_SWAP 5805#ifdef CONFIG_MEMCG_SWAP
5806static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
5807{
5808 while (!atomic_inc_not_zero(&memcg->id.ref)) {
5809 /*
5810 * The root cgroup cannot be destroyed, so it's refcount must
5811 * always be >= 1.
5812 */
5813 if (WARN_ON_ONCE(memcg == root_mem_cgroup)) {
5814 VM_BUG_ON(1);
5815 break;
5816 }
5817 memcg = parent_mem_cgroup(memcg);
5818 if (!memcg)
5819 memcg = root_mem_cgroup;
5820 }
5821 return memcg;
5822}
5823
5794/** 5824/**
5795 * mem_cgroup_swapout - transfer a memsw charge to swap 5825 * mem_cgroup_swapout - transfer a memsw charge to swap
5796 * @page: page whose memsw charge to transfer 5826 * @page: page whose memsw charge to transfer
@@ -5800,7 +5830,7 @@ subsys_initcall(mem_cgroup_init);
5800 */ 5830 */
5801void mem_cgroup_swapout(struct page *page, swp_entry_t entry) 5831void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
5802{ 5832{
5803 struct mem_cgroup *memcg; 5833 struct mem_cgroup *memcg, *swap_memcg;
5804 unsigned short oldid; 5834 unsigned short oldid;
5805 5835
5806 VM_BUG_ON_PAGE(PageLRU(page), page); 5836 VM_BUG_ON_PAGE(PageLRU(page), page);
@@ -5815,16 +5845,27 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
5815 if (!memcg) 5845 if (!memcg)
5816 return; 5846 return;
5817 5847
5818 mem_cgroup_id_get(memcg); 5848 /*
5819 oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); 5849 * In case the memcg owning these pages has been offlined and doesn't
5850 * have an ID allocated to it anymore, charge the closest online
5851 * ancestor for the swap instead and transfer the memory+swap charge.
5852 */
5853 swap_memcg = mem_cgroup_id_get_online(memcg);
5854 oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg));
5820 VM_BUG_ON_PAGE(oldid, page); 5855 VM_BUG_ON_PAGE(oldid, page);
5821 mem_cgroup_swap_statistics(memcg, true); 5856 mem_cgroup_swap_statistics(swap_memcg, true);
5822 5857
5823 page->mem_cgroup = NULL; 5858 page->mem_cgroup = NULL;
5824 5859
5825 if (!mem_cgroup_is_root(memcg)) 5860 if (!mem_cgroup_is_root(memcg))
5826 page_counter_uncharge(&memcg->memory, 1); 5861 page_counter_uncharge(&memcg->memory, 1);
5827 5862
5863 if (memcg != swap_memcg) {
5864 if (!mem_cgroup_is_root(swap_memcg))
5865 page_counter_charge(&swap_memcg->memsw, 1);
5866 page_counter_uncharge(&memcg->memsw, 1);
5867 }
5868
5828 /* 5869 /*
5829 * Interrupts should be disabled here because the caller holds the 5870 * Interrupts should be disabled here because the caller holds the
5830 * mapping->tree_lock lock which is taken with interrupts-off. It is 5871 * mapping->tree_lock lock which is taken with interrupts-off. It is
@@ -5863,11 +5904,14 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
5863 if (!memcg) 5904 if (!memcg)
5864 return 0; 5905 return 0;
5865 5906
5907 memcg = mem_cgroup_id_get_online(memcg);
5908
5866 if (!mem_cgroup_is_root(memcg) && 5909 if (!mem_cgroup_is_root(memcg) &&
5867 !page_counter_try_charge(&memcg->swap, 1, &counter)) 5910 !page_counter_try_charge(&memcg->swap, 1, &counter)) {
5911 mem_cgroup_id_put(memcg);
5868 return -ENOMEM; 5912 return -ENOMEM;
5913 }
5869 5914
5870 mem_cgroup_id_get(memcg);
5871 oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); 5915 oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
5872 VM_BUG_ON_PAGE(oldid, page); 5916 VM_BUG_ON_PAGE(oldid, page);
5873 mem_cgroup_swap_statistics(memcg, true); 5917 mem_cgroup_swap_statistics(memcg, true);