Merge branch 'for-3.11-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup fix from Tejun Heo: "During the percpu reference counting update which was merged during v3.11-rc1, the cgroup destruction path was updated so that a cgroup in the process of dying may linger on the children list, which was necessary as the cgroup should still be included in child/descendant iteration while percpu ref is being killed. Unfortunately, I forgot to update cgroup destruction path accordingly and cgroup destruction may fail spuriously with -EBUSY due to lingering dying children even when there's no live child left - e.g. "rmdir parent/child parent" will usually fail. This can be easily fixed by iterating through the children list to verify that there's no live child left. While this is very late in the release cycle, this bug is very visible to userland and I believe the fix is relatively safe. Thanks Hugh for spotting and providing fix for the issue" * 'for-3.11-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: cgroup: fix rmdir EBUSY regression in 3.11
This commit is contained in:
Коммит
41615e811b
|
@ -4480,6 +4480,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
|
||||||
struct dentry *d = cgrp->dentry;
|
struct dentry *d = cgrp->dentry;
|
||||||
struct cgroup_event *event, *tmp;
|
struct cgroup_event *event, *tmp;
|
||||||
struct cgroup_subsys *ss;
|
struct cgroup_subsys *ss;
|
||||||
|
struct cgroup *child;
|
||||||
bool empty;
|
bool empty;
|
||||||
|
|
||||||
lockdep_assert_held(&d->d_inode->i_mutex);
|
lockdep_assert_held(&d->d_inode->i_mutex);
|
||||||
|
@ -4490,11 +4491,27 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
|
||||||
* @cgrp from being removed while __put_css_set() is in progress.
|
* @cgrp from being removed while __put_css_set() is in progress.
|
||||||
*/
|
*/
|
||||||
read_lock(&css_set_lock);
|
read_lock(&css_set_lock);
|
||||||
empty = list_empty(&cgrp->cset_links) && list_empty(&cgrp->children);
|
empty = list_empty(&cgrp->cset_links);
|
||||||
read_unlock(&css_set_lock);
|
read_unlock(&css_set_lock);
|
||||||
if (!empty)
|
if (!empty)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure there's no live children. We can't test ->children
|
||||||
|
* emptiness as dead children linger on it while being destroyed;
|
||||||
|
* otherwise, "rmdir parent/child parent" may fail with -EBUSY.
|
||||||
|
*/
|
||||||
|
empty = true;
|
||||||
|
rcu_read_lock();
|
||||||
|
list_for_each_entry_rcu(child, &cgrp->children, sibling) {
|
||||||
|
empty = cgroup_is_dead(child);
|
||||||
|
if (!empty)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (!empty)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Block new css_tryget() by killing css refcnts. cgroup core
|
* Block new css_tryget() by killing css refcnts. cgroup core
|
||||||
* guarantees that, by the time ->css_offline() is invoked, no new
|
* guarantees that, by the time ->css_offline() is invoked, no new
|
||||||
|
|
Загрузка…
Ссылка в новой задаче