diff options
-rw-r--r-- | block/blk-cgroup.c | 2 | ||||
-rw-r--r-- | include/linux/cgroup.h | 8 | ||||
-rw-r--r-- | kernel/cgroup.c | 78 |
3 files changed, 51 insertions, 37 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 79fd9f4fadb7..34063739745b 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c | |||
@@ -1128,7 +1128,7 @@ void blkcg_policy_unregister(struct blkcg_policy *pol) | |||
1128 | 1128 | ||
1129 | /* kill the intf files first */ | 1129 | /* kill the intf files first */ |
1130 | if (pol->cftypes) | 1130 | if (pol->cftypes) |
1131 | cgroup_rm_cftypes(&blkio_subsys, pol->cftypes); | 1131 | cgroup_rm_cftypes(pol->cftypes); |
1132 | 1132 | ||
1133 | /* unregister and update blkgs */ | 1133 | /* unregister and update blkgs */ |
1134 | blkcg_policy[pol->plid] = NULL; | 1134 | blkcg_policy[pol->plid] = NULL; |
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 9c2b9dd9121d..5db8138a0482 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -429,6 +429,12 @@ struct cftype { | |||
429 | /* CFTYPE_* flags */ | 429 | /* CFTYPE_* flags */ |
430 | unsigned int flags; | 430 | unsigned int flags; |
431 | 431 | ||
432 | /* | ||
433 | * The subsys this file belongs to. Initialized automatically | ||
434 | * during registration. NULL for cgroup core files. | ||
435 | */ | ||
436 | struct cgroup_subsys *ss; | ||
437 | |||
432 | int (*open)(struct inode *inode, struct file *file); | 438 | int (*open)(struct inode *inode, struct file *file); |
433 | ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft, | 439 | ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft, |
434 | struct file *file, | 440 | struct file *file, |
@@ -542,7 +548,7 @@ static inline const char *cgroup_name(const struct cgroup *cgrp) | |||
542 | } | 548 | } |
543 | 549 | ||
544 | int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); | 550 | int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); |
545 | int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); | 551 | int cgroup_rm_cftypes(struct cftype *cfts); |
546 | 552 | ||
547 | bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor); | 553 | bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor); |
548 | 554 | ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 271d9a5cde5f..c4bc8dac3b1d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -219,8 +219,8 @@ static struct cftype cgroup_base_files[]; | |||
219 | 219 | ||
220 | static void cgroup_offline_fn(struct work_struct *work); | 220 | static void cgroup_offline_fn(struct work_struct *work); |
221 | static int cgroup_destroy_locked(struct cgroup *cgrp); | 221 | static int cgroup_destroy_locked(struct cgroup *cgrp); |
222 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, | 222 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], |
223 | struct cftype cfts[], bool is_add); | 223 | bool is_add); |
224 | 224 | ||
225 | /* convenient tests for these bits */ | 225 | /* convenient tests for these bits */ |
226 | static inline bool cgroup_is_dead(const struct cgroup *cgrp) | 226 | static inline bool cgroup_is_dead(const struct cgroup *cgrp) |
@@ -974,7 +974,7 @@ static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask) | |||
974 | if (!test_bit(i, &subsys_mask)) | 974 | if (!test_bit(i, &subsys_mask)) |
975 | continue; | 975 | continue; |
976 | list_for_each_entry(set, &ss->cftsets, node) | 976 | list_for_each_entry(set, &ss->cftsets, node) |
977 | cgroup_addrm_files(cgrp, NULL, set->cfts, false); | 977 | cgroup_addrm_files(cgrp, set->cfts, false); |
978 | } | 978 | } |
979 | } | 979 | } |
980 | 980 | ||
@@ -1623,7 +1623,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1623 | */ | 1623 | */ |
1624 | cred = override_creds(&init_cred); | 1624 | cred = override_creds(&init_cred); |
1625 | 1625 | ||
1626 | ret = cgroup_addrm_files(root_cgrp, NULL, cgroup_base_files, true); | 1626 | ret = cgroup_addrm_files(root_cgrp, cgroup_base_files, true); |
1627 | if (ret) | 1627 | if (ret) |
1628 | goto rm_base_files; | 1628 | goto rm_base_files; |
1629 | 1629 | ||
@@ -1681,7 +1681,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1681 | 1681 | ||
1682 | rm_base_files: | 1682 | rm_base_files: |
1683 | free_cgrp_cset_links(&tmp_links); | 1683 | free_cgrp_cset_links(&tmp_links); |
1684 | cgroup_addrm_files(&root->top_cgroup, NULL, cgroup_base_files, false); | 1684 | cgroup_addrm_files(&root->top_cgroup, cgroup_base_files, false); |
1685 | revert_creds(cred); | 1685 | revert_creds(cred); |
1686 | unlock_drop: | 1686 | unlock_drop: |
1687 | cgroup_exit_root_id(root); | 1687 | cgroup_exit_root_id(root); |
@@ -2694,8 +2694,7 @@ static umode_t cgroup_file_mode(const struct cftype *cft) | |||
2694 | return mode; | 2694 | return mode; |
2695 | } | 2695 | } |
2696 | 2696 | ||
2697 | static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys, | 2697 | static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft) |
2698 | struct cftype *cft) | ||
2699 | { | 2698 | { |
2700 | struct dentry *dir = cgrp->dentry; | 2699 | struct dentry *dir = cgrp->dentry; |
2701 | struct cgroup *parent = __d_cgrp(dir); | 2700 | struct cgroup *parent = __d_cgrp(dir); |
@@ -2705,8 +2704,8 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys, | |||
2705 | umode_t mode; | 2704 | umode_t mode; |
2706 | char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 }; | 2705 | char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 }; |
2707 | 2706 | ||
2708 | if (subsys && !(cgrp->root->flags & CGRP_ROOT_NOPREFIX)) { | 2707 | if (cft->ss && !(cgrp->root->flags & CGRP_ROOT_NOPREFIX)) { |
2709 | strcpy(name, subsys->name); | 2708 | strcpy(name, cft->ss->name); |
2710 | strcat(name, "."); | 2709 | strcat(name, "."); |
2711 | } | 2710 | } |
2712 | strcat(name, cft->name); | 2711 | strcat(name, cft->name); |
@@ -2743,17 +2742,16 @@ out: | |||
2743 | /** | 2742 | /** |
2744 | * cgroup_addrm_files - add or remove files to a cgroup directory | 2743 | * cgroup_addrm_files - add or remove files to a cgroup directory |
2745 | * @cgrp: the target cgroup | 2744 | * @cgrp: the target cgroup |
2746 | * @subsys: the subsystem of files to be added | ||
2747 | * @cfts: array of cftypes to be added | 2745 | * @cfts: array of cftypes to be added |
2748 | * @is_add: whether to add or remove | 2746 | * @is_add: whether to add or remove |
2749 | * | 2747 | * |
2750 | * Depending on @is_add, add or remove files defined by @cfts on @cgrp. | 2748 | * Depending on @is_add, add or remove files defined by @cfts on @cgrp. |
2751 | * All @cfts should belong to @subsys. For removals, this function never | 2749 | * For removals, this function never fails. If addition fails, this |
2752 | * fails. If addition fails, this function doesn't remove files already | 2750 | * function doesn't remove files already added. The caller is responsible |
2753 | * added. The caller is responsible for cleaning up. | 2751 | * for cleaning up. |
2754 | */ | 2752 | */ |
2755 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, | 2753 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], |
2756 | struct cftype cfts[], bool is_add) | 2754 | bool is_add) |
2757 | { | 2755 | { |
2758 | struct cftype *cft; | 2756 | struct cftype *cft; |
2759 | int ret; | 2757 | int ret; |
@@ -2771,7 +2769,7 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, | |||
2771 | continue; | 2769 | continue; |
2772 | 2770 | ||
2773 | if (is_add) { | 2771 | if (is_add) { |
2774 | ret = cgroup_add_file(cgrp, subsys, cft); | 2772 | ret = cgroup_add_file(cgrp, cft); |
2775 | if (ret) { | 2773 | if (ret) { |
2776 | pr_warn("cgroup_addrm_files: failed to add %s, err=%d\n", | 2774 | pr_warn("cgroup_addrm_files: failed to add %s, err=%d\n", |
2777 | cft->name, ret); | 2775 | cft->name, ret); |
@@ -2796,11 +2794,11 @@ static void cgroup_cfts_prepare(void) | |||
2796 | mutex_lock(&cgroup_mutex); | 2794 | mutex_lock(&cgroup_mutex); |
2797 | } | 2795 | } |
2798 | 2796 | ||
2799 | static int cgroup_cfts_commit(struct cgroup_subsys *ss, | 2797 | static int cgroup_cfts_commit(struct cftype *cfts, bool is_add) |
2800 | struct cftype *cfts, bool is_add) | ||
2801 | __releases(&cgroup_mutex) | 2798 | __releases(&cgroup_mutex) |
2802 | { | 2799 | { |
2803 | LIST_HEAD(pending); | 2800 | LIST_HEAD(pending); |
2801 | struct cgroup_subsys *ss = cfts[0].ss; | ||
2804 | struct cgroup *cgrp, *root = &ss->root->top_cgroup; | 2802 | struct cgroup *cgrp, *root = &ss->root->top_cgroup; |
2805 | struct super_block *sb = ss->root->sb; | 2803 | struct super_block *sb = ss->root->sb; |
2806 | struct dentry *prev = NULL; | 2804 | struct dentry *prev = NULL; |
@@ -2828,7 +2826,7 @@ static int cgroup_cfts_commit(struct cgroup_subsys *ss, | |||
2828 | inode = root->dentry->d_inode; | 2826 | inode = root->dentry->d_inode; |
2829 | mutex_lock(&inode->i_mutex); | 2827 | mutex_lock(&inode->i_mutex); |
2830 | mutex_lock(&cgroup_mutex); | 2828 | mutex_lock(&cgroup_mutex); |
2831 | ret = cgroup_addrm_files(root, ss, cfts, is_add); | 2829 | ret = cgroup_addrm_files(root, cfts, is_add); |
2832 | mutex_unlock(&cgroup_mutex); | 2830 | mutex_unlock(&cgroup_mutex); |
2833 | mutex_unlock(&inode->i_mutex); | 2831 | mutex_unlock(&inode->i_mutex); |
2834 | 2832 | ||
@@ -2851,7 +2849,7 @@ static int cgroup_cfts_commit(struct cgroup_subsys *ss, | |||
2851 | mutex_lock(&inode->i_mutex); | 2849 | mutex_lock(&inode->i_mutex); |
2852 | mutex_lock(&cgroup_mutex); | 2850 | mutex_lock(&cgroup_mutex); |
2853 | if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) | 2851 | if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) |
2854 | ret = cgroup_addrm_files(cgrp, ss, cfts, is_add); | 2852 | ret = cgroup_addrm_files(cgrp, cfts, is_add); |
2855 | mutex_unlock(&cgroup_mutex); | 2853 | mutex_unlock(&cgroup_mutex); |
2856 | mutex_unlock(&inode->i_mutex); | 2854 | mutex_unlock(&inode->i_mutex); |
2857 | 2855 | ||
@@ -2883,51 +2881,56 @@ out_deact: | |||
2883 | int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) | 2881 | int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) |
2884 | { | 2882 | { |
2885 | struct cftype_set *set; | 2883 | struct cftype_set *set; |
2884 | struct cftype *cft; | ||
2886 | int ret; | 2885 | int ret; |
2887 | 2886 | ||
2888 | set = kzalloc(sizeof(*set), GFP_KERNEL); | 2887 | set = kzalloc(sizeof(*set), GFP_KERNEL); |
2889 | if (!set) | 2888 | if (!set) |
2890 | return -ENOMEM; | 2889 | return -ENOMEM; |
2891 | 2890 | ||
2891 | for (cft = cfts; cft->name[0] != '\0'; cft++) | ||
2892 | cft->ss = ss; | ||
2893 | |||
2892 | cgroup_cfts_prepare(); | 2894 | cgroup_cfts_prepare(); |
2893 | set->cfts = cfts; | 2895 | set->cfts = cfts; |
2894 | list_add_tail(&set->node, &ss->cftsets); | 2896 | list_add_tail(&set->node, &ss->cftsets); |
2895 | ret = cgroup_cfts_commit(ss, cfts, true); | 2897 | ret = cgroup_cfts_commit(cfts, true); |
2896 | if (ret) | 2898 | if (ret) |
2897 | cgroup_rm_cftypes(ss, cfts); | 2899 | cgroup_rm_cftypes(cfts); |
2898 | return ret; | 2900 | return ret; |
2899 | } | 2901 | } |
2900 | EXPORT_SYMBOL_GPL(cgroup_add_cftypes); | 2902 | EXPORT_SYMBOL_GPL(cgroup_add_cftypes); |
2901 | 2903 | ||
2902 | /** | 2904 | /** |
2903 | * cgroup_rm_cftypes - remove an array of cftypes from a subsystem | 2905 | * cgroup_rm_cftypes - remove an array of cftypes from a subsystem |
2904 | * @ss: target cgroup subsystem | ||
2905 | * @cfts: zero-length name terminated array of cftypes | 2906 | * @cfts: zero-length name terminated array of cftypes |
2906 | * | 2907 | * |
2907 | * Unregister @cfts from @ss. Files described by @cfts are removed from | 2908 | * Unregister @cfts. Files described by @cfts are removed from all |
2908 | * all existing cgroups to which @ss is attached and all future cgroups | 2909 | * existing cgroups and all future cgroups won't have them either. This |
2909 | * won't have them either. This function can be called anytime whether @ss | 2910 | * function can be called anytime whether @cfts' subsys is attached or not. |
2910 | * is attached or not. | ||
2911 | * | 2911 | * |
2912 | * Returns 0 on successful unregistration, -ENOENT if @cfts is not | 2912 | * Returns 0 on successful unregistration, -ENOENT if @cfts is not |
2913 | * registered with @ss. | 2913 | * registered. |
2914 | */ | 2914 | */ |
2915 | int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) | 2915 | int cgroup_rm_cftypes(struct cftype *cfts) |
2916 | { | 2916 | { |
2917 | struct cftype_set *set; | 2917 | struct cftype_set *set; |
2918 | 2918 | ||
2919 | if (!cfts || !cfts[0].ss) | ||
2920 | return -ENOENT; | ||
2921 | |||
2919 | cgroup_cfts_prepare(); | 2922 | cgroup_cfts_prepare(); |
2920 | 2923 | ||
2921 | list_for_each_entry(set, &ss->cftsets, node) { | 2924 | list_for_each_entry(set, &cfts[0].ss->cftsets, node) { |
2922 | if (set->cfts == cfts) { | 2925 | if (set->cfts == cfts) { |
2923 | list_del(&set->node); | 2926 | list_del(&set->node); |
2924 | kfree(set); | 2927 | kfree(set); |
2925 | cgroup_cfts_commit(ss, cfts, false); | 2928 | cgroup_cfts_commit(cfts, false); |
2926 | return 0; | 2929 | return 0; |
2927 | } | 2930 | } |
2928 | } | 2931 | } |
2929 | 2932 | ||
2930 | cgroup_cfts_commit(ss, NULL, false); | 2933 | cgroup_cfts_commit(NULL, false); |
2931 | return -ENOENT; | 2934 | return -ENOENT; |
2932 | } | 2935 | } |
2933 | 2936 | ||
@@ -4148,7 +4151,7 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) | |||
4148 | continue; | 4151 | continue; |
4149 | 4152 | ||
4150 | list_for_each_entry(set, &ss->cftsets, node) { | 4153 | list_for_each_entry(set, &ss->cftsets, node) { |
4151 | ret = cgroup_addrm_files(cgrp, ss, set->cfts, true); | 4154 | ret = cgroup_addrm_files(cgrp, set->cfts, true); |
4152 | if (ret < 0) | 4155 | if (ret < 0) |
4153 | goto err; | 4156 | goto err; |
4154 | } | 4157 | } |
@@ -4377,7 +4380,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
4377 | 4380 | ||
4378 | idr_replace(&root->cgroup_idr, cgrp, cgrp->id); | 4381 | idr_replace(&root->cgroup_idr, cgrp, cgrp->id); |
4379 | 4382 | ||
4380 | err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true); | 4383 | err = cgroup_addrm_files(cgrp, cgroup_base_files, true); |
4381 | if (err) | 4384 | if (err) |
4382 | goto err_destroy; | 4385 | goto err_destroy; |
4383 | 4386 | ||
@@ -4538,7 +4541,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4538 | * but we aren't quite done with @cgrp yet, so hold onto it. | 4541 | * but we aren't quite done with @cgrp yet, so hold onto it. |
4539 | */ | 4542 | */ |
4540 | cgroup_clear_dir(cgrp, cgrp->root->subsys_mask); | 4543 | cgroup_clear_dir(cgrp, cgrp->root->subsys_mask); |
4541 | cgroup_addrm_files(cgrp, NULL, cgroup_base_files, false); | 4544 | cgroup_addrm_files(cgrp, cgroup_base_files, false); |
4542 | dget(d); | 4545 | dget(d); |
4543 | cgroup_d_remove_dir(d); | 4546 | cgroup_d_remove_dir(d); |
4544 | 4547 | ||
@@ -4632,6 +4635,11 @@ static void __init_or_module cgroup_init_cftsets(struct cgroup_subsys *ss) | |||
4632 | * deregistration. | 4635 | * deregistration. |
4633 | */ | 4636 | */ |
4634 | if (ss->base_cftypes) { | 4637 | if (ss->base_cftypes) { |
4638 | struct cftype *cft; | ||
4639 | |||
4640 | for (cft = ss->base_cftypes; cft->name[0] != '\0'; cft++) | ||
4641 | cft->ss = ss; | ||
4642 | |||
4635 | ss->base_cftset.cfts = ss->base_cftypes; | 4643 | ss->base_cftset.cfts = ss->base_cftypes; |
4636 | list_add_tail(&ss->base_cftset.node, &ss->cftsets); | 4644 | list_add_tail(&ss->base_cftset.node, &ss->cftsets); |
4637 | } | 4645 | } |