From patchwork Fri May 25 09:32:07 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glauber Costa X-Patchwork-Id: 161261 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 9ED17B6EF3 for ; Fri, 25 May 2012 19:34:20 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756574Ab2EYJeS (ORCPT ); Fri, 25 May 2012 05:34:18 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:6031 "EHLO relay.sw.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752519Ab2EYJeP (ORCPT ); Fri, 25 May 2012 05:34:15 -0400 Received: from straightjacket.localdomain.ru ([10.30.18.238]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id q4P9Y5Cq008217; Fri, 25 May 2012 13:34:09 +0400 (MSK) From: Glauber Costa To: Andrew Morton Cc: , , , , , Tejun Heo , Li Zefan , David Miller , Glauber Costa , Johannes Weiner , Michal Hocko Subject: [PATCH v7 1/2] Always free struct memcg through schedule_work() Date: Fri, 25 May 2012 13:32:07 +0400 Message-Id: <1337938328-11537-2-git-send-email-glommer@parallels.com> X-Mailer: git-send-email 1.7.7.6 In-Reply-To: <1337938328-11537-1-git-send-email-glommer@parallels.com> References: <1337938328-11537-1-git-send-email-glommer@parallels.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Right now we free struct memcg with kfree right after a rcu grace period, but defer it if we need to use vfree() to get rid of that memory area. We do that by need, because we need vfree to be called in a process context. This patch unifies this behavior, by ensuring that even kfree will happen in a separate thread. The goal is to have a stable place to call the upcoming jump label destruction function outside the realm of the complicated and quite far-reaching cgroup lock (that can't be held when calling neither the cpu_hotplug.lock nor the jump_label_mutex) Signed-off-by: Glauber Costa Acked-by: Kamezawa Hiroyuki CC: Tejun Heo CC: Li Zefan CC: Johannes Weiner CC: Michal Hocko CC: Andrew Morton Acked-by: Michal Hocko --- mm/memcontrol.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 932a734..0b4b4c8 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -245,8 +245,8 @@ struct mem_cgroup { */ struct rcu_head rcu_freeing; /* - * But when using vfree(), that cannot be done at - * interrupt time, so we must then queue the work. + * We also need some space for a worker in deferred freeing. + * By the time we call it, rcu_freeing is not longer in use. */ struct work_struct work_freeing; }; @@ -4826,23 +4826,28 @@ out_free: } /* - * Helpers for freeing a vzalloc()ed mem_cgroup by RCU, + * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU, * but in process context. The work_freeing structure is overlaid * on the rcu_freeing structure, which itself is overlaid on memsw. */ -static void vfree_work(struct work_struct *work) +static void free_work(struct work_struct *work) { struct mem_cgroup *memcg; + int size = sizeof(struct mem_cgroup); memcg = container_of(work, struct mem_cgroup, work_freeing); - vfree(memcg); + if (size < PAGE_SIZE) + kfree(memcg); + else + vfree(memcg); } -static void vfree_rcu(struct rcu_head *rcu_head) + +static void free_rcu(struct rcu_head *rcu_head) { struct mem_cgroup *memcg; memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing); - INIT_WORK(&memcg->work_freeing, vfree_work); + INIT_WORK(&memcg->work_freeing, free_work); schedule_work(&memcg->work_freeing); } @@ -4868,10 +4873,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) free_mem_cgroup_per_zone_info(memcg, node); free_percpu(memcg->stat); - if (sizeof(struct mem_cgroup) < PAGE_SIZE) - kfree_rcu(memcg, rcu_freeing); - else - call_rcu(&memcg->rcu_freeing, vfree_rcu); + call_rcu(&memcg->rcu_freeing, free_rcu); } static void mem_cgroup_get(struct mem_cgroup *memcg)