Bugzilla: 1045775 Upstream-status: queued for 3.14-rc3 and stable 3.12+ Path: news.gmane.org!not-for-mail From: Michal Hocko Newsgroups: gmane.linux.kernel,gmane.linux.kernel.cgroups Subject: Re: [PATCH] cgroup: protect modifications to cgroup_idr with cgroup_mutex Date: Wed, 12 Feb 2014 10:12:38 +0100 Lines: 127 Approved: news@gmane.org Message-ID: <20140212091238.GC28085@dhcp22.suse.cz> References: <52F9D9DA.7040108@huawei.com> <20140211102032.GA11946@dhcp22.suse.cz> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1392196376 529 80.91.229.3 (12 Feb 2014 09:12:56 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 12 Feb 2014 09:12:56 +0000 (UTC) Cc: Tejun Heo , LKML , Cgroups To: Li Zefan Original-X-From: linux-kernel-owner@vger.kernel.org Wed Feb 12 10:13:03 2014 Return-path: Envelope-to: glk-linux-kernel-3@plane.gmane.org Original-Received: from vger.kernel.org ([209.132.180.67]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1WDVsM-0003po-4o for glk-linux-kernel-3@plane.gmane.org; Wed, 12 Feb 2014 10:13:02 +0100 Original-Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751758AbaBLJMs (ORCPT ); Wed, 12 Feb 2014 04:12:48 -0500 Original-Received: from cantor2.suse.de ([195.135.220.15]:34766 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750890AbaBLJMk (ORCPT ); Wed, 12 Feb 2014 04:12:40 -0500 Original-Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 216F1ABB2; Wed, 12 Feb 2014 09:12:39 +0000 (UTC) Content-Disposition: inline In-Reply-To: <20140211102032.GA11946@dhcp22.suse.cz> User-Agent: Mutt/1.5.21 (2010-09-15) Original-Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Xref: news.gmane.org gmane.linux.kernel:1646465 gmane.linux.kernel.cgroups:10357 Archived-At: Li has pointed out that my previous backport was not correct because err_unlock label releases a reference to supperblock which was not taken before idr_alloc. I've also removed cgroup_mutex from free_css_id as per Li. Fixed in this version. --- Date: Tue, 11 Feb 2014 16:05:46 +0800 From: Li Zefan Subject: [PATCH - for 3.12] cgroup: protect modifications to cgroup_idr with cgroup_mutex Setup cgroupfs like this: # mount -t cgroup -o cpuacct xxx /cgroup # mkdir /cgroup/sub1 # mkdir /cgroup/sub2 Then run these two commands: # for ((; ;)) { mkdir /cgroup/sub1/tmp && rmdir /mnt/sub1/tmp; } & # for ((; ;)) { mkdir /cgroup/sub2/tmp && rmdir /mnt/sub2/tmp; } & After seconds you may see this warning: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 25243 at lib/idr.c:527 sub_remove+0x87/0x1b0() idr_remove called for id=6 which is not allocated. ... Call Trace: [] dump_stack+0x7a/0x96 [] warn_slowpath_common+0x8c/0xc0 [] warn_slowpath_fmt+0x46/0x50 [] sub_remove+0x87/0x1b0 [] ? css_killed_work_fn+0x32/0x1b0 [] idr_remove+0x25/0xd0 [] cgroup_destroy_css_killed+0x5b/0xc0 [] css_killed_work_fn+0x130/0x1b0 [] process_one_work+0x26c/0x550 [] worker_thread+0x12e/0x3b0 [] kthread+0xe6/0xf0 [] ret_from_fork+0x7c/0xb0 ---[ end trace 2d1577ec10cf80d0 ]--- It's because allocating/removing cgroup ID is not properly synchronized. The bug was introduced when we converted cgroup_ida to cgroup_idr. While synchronization is already done inside ida_simple_{get,remove}(), users are responsible for concurrent calls to idr_{alloc,remove}(). [mhocko@suse.cz: ported to 3.12] Fixes: 4e96ee8e981b ("cgroup: convert cgroup_ida to cgroup_idr") Cc: #3.12+ Reported-by: Michal Hocko Signed-off-by: Li Zefan Signed-off-by: Michal Hocko --- include/linux/cgroup.h | 2 ++ kernel/cgroup.c | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -169,6 +169,8 @@ struct cgroup { * * The ID of the root cgroup is always 0, and a new cgroup * will be assigned with a smallest available ID. + * + * Allocating/Removing ID must be protected by cgroup_mutex. */ int id; --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4410,16 +4410,6 @@ static long cgroup_create(struct cgroup rcu_assign_pointer(cgrp->name, name); /* - * Temporarily set the pointer to NULL, so idr_find() won't return - * a half-baked cgroup. - */ - cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); - if (cgrp->id < 0) { - err = -ENOMEM; - goto err_free_name; - } - - /* * Only live parents can have children. Note that the liveliness * check isn't strictly necessary because cgroup_mkdir() and * cgroup_rmdir() are fully synchronized by i_mutex; however, do it @@ -4426,7 +4418,7 @@ static long cgroup_create(struct cgroup */ if (!cgroup_lock_live_group(parent)) { err = -ENODEV; - goto err_free_id; + goto err_free_name; } /* Grab a reference on the superblock so the hierarchy doesn't @@ -4436,6 +4428,14 @@ static long cgroup_create(struct cgroup * fs */ atomic_inc(&sb->s_active); + /* + * Temporarily set the pointer to NULL, so idr_find() won't return + * a half-baked cgroup. + */ + cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); + if (cgrp->id < 0) + goto err_unlock; + init_cgroup_housekeeping(cgrp); dentry->d_fsdata = cgrp; @@ -4542,11 +4542,11 @@ err_free_all: ss->css_free(css); } } + idr_remove(&root->cgroup_idr, cgrp->id); +err_unlock: mutex_unlock(&cgroup_mutex); /* Release the reference count that we took on the superblock */ deactivate_super(sb); -err_free_id: - idr_remove(&root->cgroup_idr, cgrp->id); err_free_name: kfree(rcu_dereference_raw(cgrp->name)); err_free_cgrp: -- Michal Hocko SUSE Labs