diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2008-11-06 15:53:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-06 18:41:19 -0500 |
commit | 24eb089950ce44603b30a3145a2c8520e2b55bb1 (patch) | |
tree | 3cccd3e15589c693c8c4e6484a938d2343ef1abc | |
parent | b41ad14c30acf023d09ac064096a4cf41248ce46 (diff) |
cgroups: fix invalid cgrp->dentry before cgroup has been completely removed
This fixes an oops when reading /proc/sched_debug.
A cgroup won't be removed completely until finishing cgroup_diput(), so we
shouldn't invalidate cgrp->dentry in cgroup_rmdir(). Otherwise, when a
group is being removed while cgroup_path() gets called, we may trigger
NULL dereference BUG.
The bug can be reproduced:
# cat test.sh
#!/bin/sh
mount -t cgroup -o cpu xxx /mnt
for (( ; ; ))
{
mkdir /mnt/sub
rmdir /mnt/sub
}
# ./test.sh &
# cat /proc/sched_debug
BUG: unable to handle kernel NULL pointer dereference at 00000038
IP: [<c045a47f>] cgroup_path+0x39/0x90
...
Call Trace:
[<c0420344>] ? print_cfs_rq+0x6e/0x75d
[<c0421160>] ? sched_debug_show+0x72d/0xc1e
...
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Paul Menage <menage@google.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: <stable@kernel.org> [2.6.26.x, 2.6.27.x]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | kernel/cgroup.c | 1 |
1 files changed, 0 insertions, 1 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 35eebd5510c2..358e77564e6f 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -2497,7 +2497,6 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) | |||
2497 | list_del(&cgrp->sibling); | 2497 | list_del(&cgrp->sibling); |
2498 | spin_lock(&cgrp->dentry->d_lock); | 2498 | spin_lock(&cgrp->dentry->d_lock); |
2499 | d = dget(cgrp->dentry); | 2499 | d = dget(cgrp->dentry); |
2500 | cgrp->dentry = NULL; | ||
2501 | spin_unlock(&d->d_lock); | 2500 | spin_unlock(&d->d_lock); |
2502 | 2501 | ||
2503 | cgroup_d_remove_dir(d); | 2502 | cgroup_d_remove_dir(d); |