diff options
author | Phil Carmody <ext-phil.2.carmody@nokia.com> | 2011-03-22 19:30:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-22 20:43:58 -0400 |
commit | 8d2587970b8bdf7c8d9208e3f4bb93182aef1a0f (patch) | |
tree | 931cacaa98583412975b4601b62fb244a5ed678d | |
parent | edd45544c6f09550df0a5491aa8a07af24767e73 (diff) |
cgroups: if you list_empty() a head then don't list_del() it
list_del() leaves poison in the prev and next pointers. The next
list_empty() will compare those poisons, and say the list isn't empty.
Any list operations that assume the node is on a list because of such a
check will be fooled into dereferencing poison. One needs to INIT the
node after the del, and fortunately there's already a wrapper for that -
list_del_init().
Some of the dels are followed by deallocations, so can be ignored, and one
can be merged with an add to make a move. Apart from that, I erred on the
side of caution in making nodes list_empty()-queriable.
Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Reviewed-by: Paul Menage <menage@google.com>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Kirill A. Shutemov <kirill@shutemov.name>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | kernel/cgroup.c | 14 |
1 files changed, 6 insertions, 8 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 95362d15128c..e31b220a743d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -1813,10 +1813,8 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | |||
1813 | 1813 | ||
1814 | /* Update the css_set linked lists if we're using them */ | 1814 | /* Update the css_set linked lists if we're using them */ |
1815 | write_lock(&css_set_lock); | 1815 | write_lock(&css_set_lock); |
1816 | if (!list_empty(&tsk->cg_list)) { | 1816 | if (!list_empty(&tsk->cg_list)) |
1817 | list_del(&tsk->cg_list); | 1817 | list_move(&tsk->cg_list, &newcg->tasks); |
1818 | list_add(&tsk->cg_list, &newcg->tasks); | ||
1819 | } | ||
1820 | write_unlock(&css_set_lock); | 1818 | write_unlock(&css_set_lock); |
1821 | 1819 | ||
1822 | for_each_subsys(root, ss) { | 1820 | for_each_subsys(root, ss) { |
@@ -3655,12 +3653,12 @@ again: | |||
3655 | spin_lock(&release_list_lock); | 3653 | spin_lock(&release_list_lock); |
3656 | set_bit(CGRP_REMOVED, &cgrp->flags); | 3654 | set_bit(CGRP_REMOVED, &cgrp->flags); |
3657 | if (!list_empty(&cgrp->release_list)) | 3655 | if (!list_empty(&cgrp->release_list)) |
3658 | list_del(&cgrp->release_list); | 3656 | list_del_init(&cgrp->release_list); |
3659 | spin_unlock(&release_list_lock); | 3657 | spin_unlock(&release_list_lock); |
3660 | 3658 | ||
3661 | cgroup_lock_hierarchy(cgrp->root); | 3659 | cgroup_lock_hierarchy(cgrp->root); |
3662 | /* delete this cgroup from parent->children */ | 3660 | /* delete this cgroup from parent->children */ |
3663 | list_del(&cgrp->sibling); | 3661 | list_del_init(&cgrp->sibling); |
3664 | cgroup_unlock_hierarchy(cgrp->root); | 3662 | cgroup_unlock_hierarchy(cgrp->root); |
3665 | 3663 | ||
3666 | d = dget(cgrp->dentry); | 3664 | d = dget(cgrp->dentry); |
@@ -3879,7 +3877,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) | |||
3879 | subsys[ss->subsys_id] = NULL; | 3877 | subsys[ss->subsys_id] = NULL; |
3880 | 3878 | ||
3881 | /* remove subsystem from rootnode's list of subsystems */ | 3879 | /* remove subsystem from rootnode's list of subsystems */ |
3882 | list_del(&ss->sibling); | 3880 | list_del_init(&ss->sibling); |
3883 | 3881 | ||
3884 | /* | 3882 | /* |
3885 | * disentangle the css from all css_sets attached to the dummytop. as | 3883 | * disentangle the css from all css_sets attached to the dummytop. as |
@@ -4241,7 +4239,7 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks) | |||
4241 | if (!list_empty(&tsk->cg_list)) { | 4239 | if (!list_empty(&tsk->cg_list)) { |
4242 | write_lock(&css_set_lock); | 4240 | write_lock(&css_set_lock); |
4243 | if (!list_empty(&tsk->cg_list)) | 4241 | if (!list_empty(&tsk->cg_list)) |
4244 | list_del(&tsk->cg_list); | 4242 | list_del_init(&tsk->cg_list); |
4245 | write_unlock(&css_set_lock); | 4243 | write_unlock(&css_set_lock); |
4246 | } | 4244 | } |
4247 | 4245 | ||