diff options
author | Tejun Heo <tj@kernel.org> | 2012-04-01 15:09:56 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-04-01 15:09:56 -0400 |
commit | 05ef1d7c4a5b6d09cadd2b8e9b3c395363d1a89c (patch) | |
tree | c63adfca7c1d6a6858cd0cecf6f4eb83775c35d8 /kernel/cgroup.c | |
parent | f6ea93723d0049ae5fbbb5292cb10c51d7a80801 (diff) |
cgroup: introduce struct cfent
This patch adds cfent (cgroup file entry) which is the association
between a cgroup and a file. This is in-cgroup representation of
files under a cgroup directory. This simplifies walking walking
cgroup files and thus cgroup_clear_directory(), which is now
implemented in two parts - cgroup_rm_file() and a loop around it.
cgroup_rm_file() will be used to implement cftype removal and cfent is
scheduled to serve cgroup specific per-file data (e.g. for sysfs-like
"sever" semantics).
v2: - cfe was freed from cgroup_rm_file() which led to use-after-free
if the file had openers at the time of removal. Moved to
cgroup_diput().
- cgroup_clear_directory() triggered WARN_ON_ONCE() if d_subdirs
wasn't empty after removing all files. This triggered
spuriously if some files were open during directory clearing.
Removed.
v3: - In cgroup_diput(), WARN_ONCE(!list_empty(&cfe->node)) could be
spuriously triggered for root cgroups because they don't go
through cgroup_clear_directory() on unmount. Don't trigger WARN
for root cgroups.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: Glauber Costa <glommer@parallels.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 113 |
1 files changed, 77 insertions, 36 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 2ab29eb381b7..7d5d1c927d9d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -148,6 +148,15 @@ struct cgroupfs_root { | |||
148 | static struct cgroupfs_root rootnode; | 148 | static struct cgroupfs_root rootnode; |
149 | 149 | ||
150 | /* | 150 | /* |
151 | * cgroupfs file entry, pointed to from leaf dentry->d_fsdata. | ||
152 | */ | ||
153 | struct cfent { | ||
154 | struct list_head node; | ||
155 | struct dentry *dentry; | ||
156 | struct cftype *type; | ||
157 | }; | ||
158 | |||
159 | /* | ||
151 | * CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when | 160 | * CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when |
152 | * cgroup_subsys->use_id != 0. | 161 | * cgroup_subsys->use_id != 0. |
153 | */ | 162 | */ |
@@ -287,11 +296,16 @@ static inline struct cgroup *__d_cgrp(struct dentry *dentry) | |||
287 | return dentry->d_fsdata; | 296 | return dentry->d_fsdata; |
288 | } | 297 | } |
289 | 298 | ||
290 | static inline struct cftype *__d_cft(struct dentry *dentry) | 299 | static inline struct cfent *__d_cfe(struct dentry *dentry) |
291 | { | 300 | { |
292 | return dentry->d_fsdata; | 301 | return dentry->d_fsdata; |
293 | } | 302 | } |
294 | 303 | ||
304 | static inline struct cftype *__d_cft(struct dentry *dentry) | ||
305 | { | ||
306 | return __d_cfe(dentry)->type; | ||
307 | } | ||
308 | |||
295 | /* the list of cgroups eligible for automatic release. Protected by | 309 | /* the list of cgroups eligible for automatic release. Protected by |
296 | * release_list_lock */ | 310 | * release_list_lock */ |
297 | static LIST_HEAD(release_list); | 311 | static LIST_HEAD(release_list); |
@@ -877,6 +891,14 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) | |||
877 | BUG_ON(!list_empty(&cgrp->pidlists)); | 891 | BUG_ON(!list_empty(&cgrp->pidlists)); |
878 | 892 | ||
879 | kfree_rcu(cgrp, rcu_head); | 893 | kfree_rcu(cgrp, rcu_head); |
894 | } else { | ||
895 | struct cfent *cfe = __d_cfe(dentry); | ||
896 | struct cgroup *cgrp = dentry->d_parent->d_fsdata; | ||
897 | |||
898 | WARN_ONCE(!list_empty(&cfe->node) && | ||
899 | cgrp != &cgrp->root->top_cgroup, | ||
900 | "cfe still linked for %s\n", cfe->type->name); | ||
901 | kfree(cfe); | ||
880 | } | 902 | } |
881 | iput(inode); | 903 | iput(inode); |
882 | } | 904 | } |
@@ -895,34 +917,36 @@ static void remove_dir(struct dentry *d) | |||
895 | dput(parent); | 917 | dput(parent); |
896 | } | 918 | } |
897 | 919 | ||
898 | static void cgroup_clear_directory(struct dentry *dentry) | 920 | static int cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft) |
899 | { | 921 | { |
900 | struct list_head *node; | 922 | struct cfent *cfe; |
901 | 923 | ||
902 | BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); | 924 | lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex); |
903 | spin_lock(&dentry->d_lock); | 925 | lockdep_assert_held(&cgroup_mutex); |
904 | node = dentry->d_subdirs.next; | 926 | |
905 | while (node != &dentry->d_subdirs) { | 927 | list_for_each_entry(cfe, &cgrp->files, node) { |
906 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); | 928 | struct dentry *d = cfe->dentry; |
907 | 929 | ||
908 | spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); | 930 | if (cft && cfe->type != cft) |
909 | list_del_init(node); | 931 | continue; |
910 | if (d->d_inode) { | 932 | |
911 | /* This should never be called on a cgroup | 933 | dget(d); |
912 | * directory with child cgroups */ | 934 | d_delete(d); |
913 | BUG_ON(d->d_inode->i_mode & S_IFDIR); | 935 | simple_unlink(d->d_inode, d); |
914 | dget_dlock(d); | 936 | list_del_init(&cfe->node); |
915 | spin_unlock(&d->d_lock); | 937 | dput(d); |
916 | spin_unlock(&dentry->d_lock); | 938 | |
917 | d_delete(d); | 939 | return 0; |
918 | simple_unlink(dentry->d_inode, d); | ||
919 | dput(d); | ||
920 | spin_lock(&dentry->d_lock); | ||
921 | } else | ||
922 | spin_unlock(&d->d_lock); | ||
923 | node = dentry->d_subdirs.next; | ||
924 | } | 940 | } |
925 | spin_unlock(&dentry->d_lock); | 941 | return -ENOENT; |
942 | } | ||
943 | |||
944 | static void cgroup_clear_directory(struct dentry *dir) | ||
945 | { | ||
946 | struct cgroup *cgrp = __d_cgrp(dir); | ||
947 | |||
948 | while (!list_empty(&cgrp->files)) | ||
949 | cgroup_rm_file(cgrp, NULL); | ||
926 | } | 950 | } |
927 | 951 | ||
928 | /* | 952 | /* |
@@ -1352,6 +1376,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) | |||
1352 | { | 1376 | { |
1353 | INIT_LIST_HEAD(&cgrp->sibling); | 1377 | INIT_LIST_HEAD(&cgrp->sibling); |
1354 | INIT_LIST_HEAD(&cgrp->children); | 1378 | INIT_LIST_HEAD(&cgrp->children); |
1379 | INIT_LIST_HEAD(&cgrp->files); | ||
1355 | INIT_LIST_HEAD(&cgrp->css_sets); | 1380 | INIT_LIST_HEAD(&cgrp->css_sets); |
1356 | INIT_LIST_HEAD(&cgrp->release_list); | 1381 | INIT_LIST_HEAD(&cgrp->release_list); |
1357 | INIT_LIST_HEAD(&cgrp->pidlists); | 1382 | INIT_LIST_HEAD(&cgrp->pidlists); |
@@ -2619,7 +2644,9 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys, | |||
2619 | const struct cftype *cft) | 2644 | const struct cftype *cft) |
2620 | { | 2645 | { |
2621 | struct dentry *dir = cgrp->dentry; | 2646 | struct dentry *dir = cgrp->dentry; |
2647 | struct cgroup *parent = __d_cgrp(dir); | ||
2622 | struct dentry *dentry; | 2648 | struct dentry *dentry; |
2649 | struct cfent *cfe; | ||
2623 | int error; | 2650 | int error; |
2624 | umode_t mode; | 2651 | umode_t mode; |
2625 | char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 }; | 2652 | char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 }; |
@@ -2635,17 +2662,31 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys, | |||
2635 | strcat(name, "."); | 2662 | strcat(name, "."); |
2636 | } | 2663 | } |
2637 | strcat(name, cft->name); | 2664 | strcat(name, cft->name); |
2665 | |||
2638 | BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex)); | 2666 | BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex)); |
2667 | |||
2668 | cfe = kzalloc(sizeof(*cfe), GFP_KERNEL); | ||
2669 | if (!cfe) | ||
2670 | return -ENOMEM; | ||
2671 | |||
2639 | dentry = lookup_one_len(name, dir, strlen(name)); | 2672 | dentry = lookup_one_len(name, dir, strlen(name)); |
2640 | if (!IS_ERR(dentry)) { | 2673 | if (IS_ERR(dentry)) { |
2641 | mode = cgroup_file_mode(cft); | ||
2642 | error = cgroup_create_file(dentry, mode | S_IFREG, | ||
2643 | cgrp->root->sb); | ||
2644 | if (!error) | ||
2645 | dentry->d_fsdata = (void *)cft; | ||
2646 | dput(dentry); | ||
2647 | } else | ||
2648 | error = PTR_ERR(dentry); | 2674 | error = PTR_ERR(dentry); |
2675 | goto out; | ||
2676 | } | ||
2677 | |||
2678 | mode = cgroup_file_mode(cft); | ||
2679 | error = cgroup_create_file(dentry, mode | S_IFREG, cgrp->root->sb); | ||
2680 | if (!error) { | ||
2681 | cfe->type = (void *)cft; | ||
2682 | cfe->dentry = dentry; | ||
2683 | dentry->d_fsdata = cfe; | ||
2684 | list_add_tail(&cfe->node, &parent->files); | ||
2685 | cfe = NULL; | ||
2686 | } | ||
2687 | dput(dentry); | ||
2688 | out: | ||
2689 | kfree(cfe); | ||
2649 | return error; | 2690 | return error; |
2650 | } | 2691 | } |
2651 | 2692 | ||