From: Greg Kroah-Hartman Date: Sun, 14 Aug 2016 16:15:24 +0000 (+0200) Subject: 4.7-stable patches X-Git-Tag: v3.14.76~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c8846549456a1b0d8333a8e241d3b0331a16d765;p=thirdparty%2Fkernel%2Fstable-queue.git 4.7-stable patches added patches: mm-memcontrol-fix-memcg-id-ref-counter-on-swap-charge-move.patch mm-memcontrol-fix-swap-counter-leak-on-swapout-from-offline-cgroup.patch --- diff --git a/queue-4.7/mm-memcontrol-fix-memcg-id-ref-counter-on-swap-charge-move.patch b/queue-4.7/mm-memcontrol-fix-memcg-id-ref-counter-on-swap-charge-move.patch new file mode 100644 index 00000000000..3c138ffeeb7 --- /dev/null +++ b/queue-4.7/mm-memcontrol-fix-memcg-id-ref-counter-on-swap-charge-move.patch @@ -0,0 +1,91 @@ +From 615d66c37c755c49ce022c9e5ac0875d27d2603d Mon Sep 17 00:00:00 2001 +From: Vladimir Davydov +Date: Thu, 11 Aug 2016 15:33:03 -0700 +Subject: mm: memcontrol: fix memcg id ref counter on swap charge move + +From: Vladimir Davydov + +commit 615d66c37c755c49ce022c9e5ac0875d27d2603d upstream. + +Since commit 73f576c04b94 ("mm: memcontrol: fix cgroup creation failure +after many small jobs") swap entries do not pin memcg->css.refcnt +directly. Instead, they pin memcg->id.ref. So we should adjust the +reference counters accordingly when moving swap charges between cgroups. + +Fixes: 73f576c04b941 ("mm: memcontrol: fix cgroup creation failure after many small jobs") +Link: http://lkml.kernel.org/r/9ce297c64954a42dc90b543bc76106c4a94f07e8.1470219853.git.vdavydov@virtuozzo.com +Signed-off-by: Vladimir Davydov +Acked-by: Michal Hocko +Acked-by: Johannes Weiner +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/memcontrol.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -4083,9 +4083,9 @@ static struct cftype mem_cgroup_legacy_f + + static DEFINE_IDR(mem_cgroup_idr); + +-static void mem_cgroup_id_get(struct mem_cgroup *memcg) ++static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n) + { +- atomic_inc(&memcg->id.ref); ++ atomic_add(n, &memcg->id.ref); + } + + static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg) +@@ -4106,9 +4106,9 @@ static struct mem_cgroup *mem_cgroup_id_ + return memcg; + } + +-static void mem_cgroup_id_put(struct mem_cgroup *memcg) ++static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n) + { +- if (atomic_dec_and_test(&memcg->id.ref)) { ++ if (atomic_sub_and_test(n, &memcg->id.ref)) { + idr_remove(&mem_cgroup_idr, memcg->id.id); + memcg->id.id = 0; + +@@ -4117,6 +4117,16 @@ static void mem_cgroup_id_put(struct mem + } + } + ++static inline void mem_cgroup_id_get(struct mem_cgroup *memcg) ++{ ++ mem_cgroup_id_get_many(memcg, 1); ++} ++ ++static inline void mem_cgroup_id_put(struct mem_cgroup *memcg) ++{ ++ mem_cgroup_id_put_many(memcg, 1); ++} ++ + /** + * mem_cgroup_from_id - look up a memcg from a memcg id + * @id: the memcg id to look up +@@ -4754,6 +4764,8 @@ static void __mem_cgroup_clear_mc(void) + if (!mem_cgroup_is_root(mc.from)) + page_counter_uncharge(&mc.from->memsw, mc.moved_swap); + ++ mem_cgroup_id_put_many(mc.from, mc.moved_swap); ++ + /* + * we charged both to->memory and to->memsw, so we + * should uncharge to->memory. +@@ -4761,9 +4773,9 @@ static void __mem_cgroup_clear_mc(void) + if (!mem_cgroup_is_root(mc.to)) + page_counter_uncharge(&mc.to->memory, mc.moved_swap); + +- css_put_many(&mc.from->css, mc.moved_swap); ++ mem_cgroup_id_get_many(mc.to, mc.moved_swap); ++ css_put_many(&mc.to->css, mc.moved_swap); + +- /* we've already done css_get(mc.to) */ + mc.moved_swap = 0; + } + memcg_oom_recover(from); diff --git a/queue-4.7/mm-memcontrol-fix-swap-counter-leak-on-swapout-from-offline-cgroup.patch b/queue-4.7/mm-memcontrol-fix-swap-counter-leak-on-swapout-from-offline-cgroup.patch new file mode 100644 index 00000000000..baac1e61660 --- /dev/null +++ b/queue-4.7/mm-memcontrol-fix-swap-counter-leak-on-swapout-from-offline-cgroup.patch @@ -0,0 +1,119 @@ +From 1f47b61fb4077936465dcde872a4e5cc4fe708da Mon Sep 17 00:00:00 2001 +From: Vladimir Davydov +Date: Thu, 11 Aug 2016 15:33:00 -0700 +Subject: mm: memcontrol: fix swap counter leak on swapout from offline cgroup + +From: Vladimir Davydov + +commit 1f47b61fb4077936465dcde872a4e5cc4fe708da upstream. + +An offline memory cgroup might have anonymous memory or shmem left +charged to it and no swap. Since only swap entries pin the id of an +offline cgroup, such a cgroup will have no id and so an attempt to +swapout its anon/shmem will not store memory cgroup info in the swap +cgroup map. As a result, memcg->swap or memcg->memsw will never get +uncharged from it and any of its ascendants. + +Fix this by always charging swapout to the first ancestor cgroup that +hasn't released its id yet. + +[hannes@cmpxchg.org: add comment to mem_cgroup_swapout] +[vdavydov@virtuozzo.com: use WARN_ON_ONCE() in mem_cgroup_id_get_online()] + Link: http://lkml.kernel.org/r/20160803123445.GJ13263@esperanza +Fixes: 73f576c04b941 ("mm: memcontrol: fix cgroup creation failure after many small jobs") +Link: http://lkml.kernel.org/r/5336daa5c9a32e776067773d9da655d2dc126491.1470219853.git.vdavydov@virtuozzo.com +Signed-off-by: Vladimir Davydov +Acked-by: Johannes Weiner +Acked-by: Michal Hocko +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/memcontrol.c | 44 ++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 38 insertions(+), 6 deletions(-) + +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -4088,6 +4088,24 @@ static void mem_cgroup_id_get(struct mem + atomic_inc(&memcg->id.ref); + } + ++static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg) ++{ ++ while (!atomic_inc_not_zero(&memcg->id.ref)) { ++ /* ++ * The root cgroup cannot be destroyed, so it's refcount must ++ * always be >= 1. ++ */ ++ if (WARN_ON_ONCE(memcg == root_mem_cgroup)) { ++ VM_BUG_ON(1); ++ break; ++ } ++ memcg = parent_mem_cgroup(memcg); ++ if (!memcg) ++ memcg = root_mem_cgroup; ++ } ++ return memcg; ++} ++ + static void mem_cgroup_id_put(struct mem_cgroup *memcg) + { + if (atomic_dec_and_test(&memcg->id.ref)) { +@@ -5805,7 +5823,7 @@ subsys_initcall(mem_cgroup_init); + */ + void mem_cgroup_swapout(struct page *page, swp_entry_t entry) + { +- struct mem_cgroup *memcg; ++ struct mem_cgroup *memcg, *swap_memcg; + unsigned short oldid; + + VM_BUG_ON_PAGE(PageLRU(page), page); +@@ -5820,16 +5838,27 @@ void mem_cgroup_swapout(struct page *pag + if (!memcg) + return; + +- mem_cgroup_id_get(memcg); +- oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); ++ /* ++ * In case the memcg owning these pages has been offlined and doesn't ++ * have an ID allocated to it anymore, charge the closest online ++ * ancestor for the swap instead and transfer the memory+swap charge. ++ */ ++ swap_memcg = mem_cgroup_id_get_online(memcg); ++ oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg)); + VM_BUG_ON_PAGE(oldid, page); +- mem_cgroup_swap_statistics(memcg, true); ++ mem_cgroup_swap_statistics(swap_memcg, true); + + page->mem_cgroup = NULL; + + if (!mem_cgroup_is_root(memcg)) + page_counter_uncharge(&memcg->memory, 1); + ++ if (memcg != swap_memcg) { ++ if (!mem_cgroup_is_root(swap_memcg)) ++ page_counter_charge(&swap_memcg->memsw, 1); ++ page_counter_uncharge(&memcg->memsw, 1); ++ } ++ + /* + * Interrupts should be disabled here because the caller holds the + * mapping->tree_lock lock which is taken with interrupts-off. It is +@@ -5868,11 +5897,14 @@ int mem_cgroup_try_charge_swap(struct pa + if (!memcg) + return 0; + ++ memcg = mem_cgroup_id_get_online(memcg); ++ + if (!mem_cgroup_is_root(memcg) && +- !page_counter_try_charge(&memcg->swap, 1, &counter)) ++ !page_counter_try_charge(&memcg->swap, 1, &counter)) { ++ mem_cgroup_id_put(memcg); + return -ENOMEM; ++ } + +- mem_cgroup_id_get(memcg); + oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); + VM_BUG_ON_PAGE(oldid, page); + mem_cgroup_swap_statistics(memcg, true); diff --git a/queue-4.7/series b/queue-4.7/series index c3c4fcd7339..f5cf8820bb0 100644 --- a/queue-4.7/series +++ b/queue-4.7/series @@ -16,3 +16,5 @@ keys-64-bit-mips-needs-to-use-compat_sys_keyctl-for-32-bit-userspace.patch ib-hfi1-disable-by-default.patch apparmor-fix-ref-count-leak-when-profile-sha1-hash-is-read.patch random-strengthen-input-validation-for-rndaddtoentcnt.patch +mm-memcontrol-fix-swap-counter-leak-on-swapout-from-offline-cgroup.patch +mm-memcontrol-fix-memcg-id-ref-counter-on-swap-charge-move.patch