diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index eb7af39350c6..7b4705b51d4a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -877,23 +877,31 @@ static void cgroup_clear_directory(struct dentry *dentry) | |||
877 | 877 | ||
878 | BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); | 878 | BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); |
879 | spin_lock(&dcache_lock); | 879 | spin_lock(&dcache_lock); |
880 | spin_lock(&dentry->d_lock); | ||
880 | node = dentry->d_subdirs.next; | 881 | node = dentry->d_subdirs.next; |
881 | while (node != &dentry->d_subdirs) { | 882 | while (node != &dentry->d_subdirs) { |
882 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); | 883 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); |
884 | |||
885 | spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); | ||
883 | list_del_init(node); | 886 | list_del_init(node); |
884 | if (d->d_inode) { | 887 | if (d->d_inode) { |
885 | /* This should never be called on a cgroup | 888 | /* This should never be called on a cgroup |
886 | * directory with child cgroups */ | 889 | * directory with child cgroups */ |
887 | BUG_ON(d->d_inode->i_mode & S_IFDIR); | 890 | BUG_ON(d->d_inode->i_mode & S_IFDIR); |
888 | d = dget_locked(d); | 891 | dget_locked_dlock(d); |
892 | spin_unlock(&d->d_lock); | ||
893 | spin_unlock(&dentry->d_lock); | ||
889 | spin_unlock(&dcache_lock); | 894 | spin_unlock(&dcache_lock); |
890 | d_delete(d); | 895 | d_delete(d); |
891 | simple_unlink(dentry->d_inode, d); | 896 | simple_unlink(dentry->d_inode, d); |
892 | dput(d); | 897 | dput(d); |
893 | spin_lock(&dcache_lock); | 898 | spin_lock(&dcache_lock); |
894 | } | 899 | spin_lock(&dentry->d_lock); |
900 | } else | ||
901 | spin_unlock(&d->d_lock); | ||
895 | node = dentry->d_subdirs.next; | 902 | node = dentry->d_subdirs.next; |
896 | } | 903 | } |
904 | spin_unlock(&dentry->d_lock); | ||
897 | spin_unlock(&dcache_lock); | 905 | spin_unlock(&dcache_lock); |
898 | } | 906 | } |
899 | 907 | ||
@@ -902,10 +910,17 @@ static void cgroup_clear_directory(struct dentry *dentry) | |||
902 | */ | 910 | */ |
903 | static void cgroup_d_remove_dir(struct dentry *dentry) | 911 | static void cgroup_d_remove_dir(struct dentry *dentry) |
904 | { | 912 | { |
913 | struct dentry *parent; | ||
914 | |||
905 | cgroup_clear_directory(dentry); | 915 | cgroup_clear_directory(dentry); |
906 | 916 | ||
907 | spin_lock(&dcache_lock); | 917 | spin_lock(&dcache_lock); |
918 | parent = dentry->d_parent; | ||
919 | spin_lock(&parent->d_lock); | ||
920 | spin_lock(&dentry->d_lock); | ||
908 | list_del_init(&dentry->d_u.d_child); | 921 | list_del_init(&dentry->d_u.d_child); |
922 | spin_unlock(&dentry->d_lock); | ||
923 | spin_unlock(&parent->d_lock); | ||
909 | spin_unlock(&dcache_lock); | 924 | spin_unlock(&dcache_lock); |
910 | remove_dir(dentry); | 925 | remove_dir(dentry); |
911 | } | 926 | } |