aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c19
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 */
903static void cgroup_d_remove_dir(struct dentry *dentry) 911static 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}