diff options
author | Tejun Heo <tj@kernel.org> | 2013-11-22 18:32:25 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-11-22 18:32:25 -0500 |
commit | edab95103d3a1eb5e3faf977eae4ad0b5bf5669c (patch) | |
tree | 812c111f94b0ae31bf88b49e7c37a7f5ba353eef /kernel/cgroup.c | |
parent | e5fca243abae1445afbfceebda5f08462ef869d3 (diff) | |
parent | b36824c75c7855585d6476eef2b234f6e0e68872 (diff) |
cgroup: Merge branch 'memcg_event' into for-3.14
Merge v3.12 based patch series to move cgroup_event implementation to
memcg into for-3.14. The following two commits cause a conflict in
kernel/cgroup.c
2ff2a7d03bbe4 ("cgroup: kill css_id")
79bd9814e5ec9 ("cgroup, memcg: move cgroup_event implementation to memcg")
Each patch removes a struct definition from kernel/cgroup.c. As the
two are adjacent, they cause a context conflict. Easily resolved by
removing both structs.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 259 |
1 files changed, 0 insertions, 259 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a7b98ee35ef7..be42967f4f1a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -56,11 +56,8 @@ | |||
56 | #include <linux/pid_namespace.h> | 56 | #include <linux/pid_namespace.h> |
57 | #include <linux/idr.h> | 57 | #include <linux/idr.h> |
58 | #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */ | 58 | #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */ |
59 | #include <linux/eventfd.h> | ||
60 | #include <linux/poll.h> | ||
61 | #include <linux/flex_array.h> /* used in cgroup_attach_task */ | 59 | #include <linux/flex_array.h> /* used in cgroup_attach_task */ |
62 | #include <linux/kthread.h> | 60 | #include <linux/kthread.h> |
63 | #include <linux/file.h> | ||
64 | 61 | ||
65 | #include <linux/atomic.h> | 62 | #include <linux/atomic.h> |
66 | 63 | ||
@@ -132,36 +129,6 @@ struct cfent { | |||
132 | struct simple_xattrs xattrs; | 129 | struct simple_xattrs xattrs; |
133 | }; | 130 | }; |
134 | 131 | ||
135 | /* | ||
136 | * cgroup_event represents events which userspace want to receive. | ||
137 | */ | ||
138 | struct cgroup_event { | ||
139 | /* | ||
140 | * css which the event belongs to. | ||
141 | */ | ||
142 | struct cgroup_subsys_state *css; | ||
143 | /* | ||
144 | * Control file which the event associated. | ||
145 | */ | ||
146 | struct cftype *cft; | ||
147 | /* | ||
148 | * eventfd to signal userspace about the event. | ||
149 | */ | ||
150 | struct eventfd_ctx *eventfd; | ||
151 | /* | ||
152 | * Each of these stored in a list by the cgroup. | ||
153 | */ | ||
154 | struct list_head list; | ||
155 | /* | ||
156 | * All fields below needed to unregister event when | ||
157 | * userspace closes eventfd. | ||
158 | */ | ||
159 | poll_table pt; | ||
160 | wait_queue_head_t *wqh; | ||
161 | wait_queue_t wait; | ||
162 | struct work_struct remove; | ||
163 | }; | ||
164 | |||
165 | /* The list of hierarchy roots */ | 132 | /* The list of hierarchy roots */ |
166 | 133 | ||
167 | static LIST_HEAD(cgroup_roots); | 134 | static LIST_HEAD(cgroup_roots); |
@@ -1351,8 +1318,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) | |||
1351 | INIT_LIST_HEAD(&cgrp->pidlists); | 1318 | INIT_LIST_HEAD(&cgrp->pidlists); |
1352 | mutex_init(&cgrp->pidlist_mutex); | 1319 | mutex_init(&cgrp->pidlist_mutex); |
1353 | cgrp->dummy_css.cgroup = cgrp; | 1320 | cgrp->dummy_css.cgroup = cgrp; |
1354 | INIT_LIST_HEAD(&cgrp->event_list); | ||
1355 | spin_lock_init(&cgrp->event_list_lock); | ||
1356 | simple_xattrs_init(&cgrp->xattrs); | 1321 | simple_xattrs_init(&cgrp->xattrs); |
1357 | } | 1322 | } |
1358 | 1323 | ||
@@ -2626,16 +2591,6 @@ static const struct inode_operations cgroup_dir_inode_operations = { | |||
2626 | .removexattr = cgroup_removexattr, | 2591 | .removexattr = cgroup_removexattr, |
2627 | }; | 2592 | }; |
2628 | 2593 | ||
2629 | /* | ||
2630 | * Check if a file is a control file | ||
2631 | */ | ||
2632 | static inline struct cftype *__file_cft(struct file *file) | ||
2633 | { | ||
2634 | if (file_inode(file)->i_fop != &cgroup_file_operations) | ||
2635 | return ERR_PTR(-EINVAL); | ||
2636 | return __d_cft(file->f_dentry); | ||
2637 | } | ||
2638 | |||
2639 | static int cgroup_create_file(struct dentry *dentry, umode_t mode, | 2594 | static int cgroup_create_file(struct dentry *dentry, umode_t mode, |
2640 | struct super_block *sb) | 2595 | struct super_block *sb) |
2641 | { | 2596 | { |
@@ -3915,202 +3870,6 @@ static void cgroup_dput(struct cgroup *cgrp) | |||
3915 | deactivate_super(sb); | 3870 | deactivate_super(sb); |
3916 | } | 3871 | } |
3917 | 3872 | ||
3918 | /* | ||
3919 | * Unregister event and free resources. | ||
3920 | * | ||
3921 | * Gets called from workqueue. | ||
3922 | */ | ||
3923 | static void cgroup_event_remove(struct work_struct *work) | ||
3924 | { | ||
3925 | struct cgroup_event *event = container_of(work, struct cgroup_event, | ||
3926 | remove); | ||
3927 | struct cgroup_subsys_state *css = event->css; | ||
3928 | |||
3929 | remove_wait_queue(event->wqh, &event->wait); | ||
3930 | |||
3931 | event->cft->unregister_event(css, event->cft, event->eventfd); | ||
3932 | |||
3933 | /* Notify userspace the event is going away. */ | ||
3934 | eventfd_signal(event->eventfd, 1); | ||
3935 | |||
3936 | eventfd_ctx_put(event->eventfd); | ||
3937 | kfree(event); | ||
3938 | css_put(css); | ||
3939 | } | ||
3940 | |||
3941 | /* | ||
3942 | * Gets called on POLLHUP on eventfd when user closes it. | ||
3943 | * | ||
3944 | * Called with wqh->lock held and interrupts disabled. | ||
3945 | */ | ||
3946 | static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, | ||
3947 | int sync, void *key) | ||
3948 | { | ||
3949 | struct cgroup_event *event = container_of(wait, | ||
3950 | struct cgroup_event, wait); | ||
3951 | struct cgroup *cgrp = event->css->cgroup; | ||
3952 | unsigned long flags = (unsigned long)key; | ||
3953 | |||
3954 | if (flags & POLLHUP) { | ||
3955 | /* | ||
3956 | * If the event has been detached at cgroup removal, we | ||
3957 | * can simply return knowing the other side will cleanup | ||
3958 | * for us. | ||
3959 | * | ||
3960 | * We can't race against event freeing since the other | ||
3961 | * side will require wqh->lock via remove_wait_queue(), | ||
3962 | * which we hold. | ||
3963 | */ | ||
3964 | spin_lock(&cgrp->event_list_lock); | ||
3965 | if (!list_empty(&event->list)) { | ||
3966 | list_del_init(&event->list); | ||
3967 | /* | ||
3968 | * We are in atomic context, but cgroup_event_remove() | ||
3969 | * may sleep, so we have to call it in workqueue. | ||
3970 | */ | ||
3971 | schedule_work(&event->remove); | ||
3972 | } | ||
3973 | spin_unlock(&cgrp->event_list_lock); | ||
3974 | } | ||
3975 | |||
3976 | return 0; | ||
3977 | } | ||
3978 | |||
3979 | static void cgroup_event_ptable_queue_proc(struct file *file, | ||
3980 | wait_queue_head_t *wqh, poll_table *pt) | ||
3981 | { | ||
3982 | struct cgroup_event *event = container_of(pt, | ||
3983 | struct cgroup_event, pt); | ||
3984 | |||
3985 | event->wqh = wqh; | ||
3986 | add_wait_queue(wqh, &event->wait); | ||
3987 | } | ||
3988 | |||
3989 | /* | ||
3990 | * Parse input and register new cgroup event handler. | ||
3991 | * | ||
3992 | * Input must be in format '<event_fd> <control_fd> <args>'. | ||
3993 | * Interpretation of args is defined by control file implementation. | ||
3994 | */ | ||
3995 | static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css, | ||
3996 | struct cftype *cft, const char *buffer) | ||
3997 | { | ||
3998 | struct cgroup *cgrp = dummy_css->cgroup; | ||
3999 | struct cgroup_event *event; | ||
4000 | struct cgroup_subsys_state *cfile_css; | ||
4001 | unsigned int efd, cfd; | ||
4002 | struct fd efile; | ||
4003 | struct fd cfile; | ||
4004 | char *endp; | ||
4005 | int ret; | ||
4006 | |||
4007 | efd = simple_strtoul(buffer, &endp, 10); | ||
4008 | if (*endp != ' ') | ||
4009 | return -EINVAL; | ||
4010 | buffer = endp + 1; | ||
4011 | |||
4012 | cfd = simple_strtoul(buffer, &endp, 10); | ||
4013 | if ((*endp != ' ') && (*endp != '\0')) | ||
4014 | return -EINVAL; | ||
4015 | buffer = endp + 1; | ||
4016 | |||
4017 | event = kzalloc(sizeof(*event), GFP_KERNEL); | ||
4018 | if (!event) | ||
4019 | return -ENOMEM; | ||
4020 | |||
4021 | INIT_LIST_HEAD(&event->list); | ||
4022 | init_poll_funcptr(&event->pt, cgroup_event_ptable_queue_proc); | ||
4023 | init_waitqueue_func_entry(&event->wait, cgroup_event_wake); | ||
4024 | INIT_WORK(&event->remove, cgroup_event_remove); | ||
4025 | |||
4026 | efile = fdget(efd); | ||
4027 | if (!efile.file) { | ||
4028 | ret = -EBADF; | ||
4029 | goto out_kfree; | ||
4030 | } | ||
4031 | |||
4032 | event->eventfd = eventfd_ctx_fileget(efile.file); | ||
4033 | if (IS_ERR(event->eventfd)) { | ||
4034 | ret = PTR_ERR(event->eventfd); | ||
4035 | goto out_put_efile; | ||
4036 | } | ||
4037 | |||
4038 | cfile = fdget(cfd); | ||
4039 | if (!cfile.file) { | ||
4040 | ret = -EBADF; | ||
4041 | goto out_put_eventfd; | ||
4042 | } | ||
4043 | |||
4044 | /* the process need read permission on control file */ | ||
4045 | /* AV: shouldn't we check that it's been opened for read instead? */ | ||
4046 | ret = inode_permission(file_inode(cfile.file), MAY_READ); | ||
4047 | if (ret < 0) | ||
4048 | goto out_put_cfile; | ||
4049 | |||
4050 | event->cft = __file_cft(cfile.file); | ||
4051 | if (IS_ERR(event->cft)) { | ||
4052 | ret = PTR_ERR(event->cft); | ||
4053 | goto out_put_cfile; | ||
4054 | } | ||
4055 | |||
4056 | if (!event->cft->ss) { | ||
4057 | ret = -EBADF; | ||
4058 | goto out_put_cfile; | ||
4059 | } | ||
4060 | |||
4061 | /* | ||
4062 | * Determine the css of @cfile, verify it belongs to the same | ||
4063 | * cgroup as cgroup.event_control, and associate @event with it. | ||
4064 | * Remaining events are automatically removed on cgroup destruction | ||
4065 | * but the removal is asynchronous, so take an extra ref. | ||
4066 | */ | ||
4067 | rcu_read_lock(); | ||
4068 | |||
4069 | ret = -EINVAL; | ||
4070 | event->css = cgroup_css(cgrp, event->cft->ss); | ||
4071 | cfile_css = css_from_dir(cfile.file->f_dentry->d_parent, event->cft->ss); | ||
4072 | if (event->css && event->css == cfile_css && css_tryget(event->css)) | ||
4073 | ret = 0; | ||
4074 | |||
4075 | rcu_read_unlock(); | ||
4076 | if (ret) | ||
4077 | goto out_put_cfile; | ||
4078 | |||
4079 | if (!event->cft->register_event || !event->cft->unregister_event) { | ||
4080 | ret = -EINVAL; | ||
4081 | goto out_put_css; | ||
4082 | } | ||
4083 | |||
4084 | ret = event->cft->register_event(event->css, event->cft, | ||
4085 | event->eventfd, buffer); | ||
4086 | if (ret) | ||
4087 | goto out_put_css; | ||
4088 | |||
4089 | efile.file->f_op->poll(efile.file, &event->pt); | ||
4090 | |||
4091 | spin_lock(&cgrp->event_list_lock); | ||
4092 | list_add(&event->list, &cgrp->event_list); | ||
4093 | spin_unlock(&cgrp->event_list_lock); | ||
4094 | |||
4095 | fdput(cfile); | ||
4096 | fdput(efile); | ||
4097 | |||
4098 | return 0; | ||
4099 | |||
4100 | out_put_css: | ||
4101 | css_put(event->css); | ||
4102 | out_put_cfile: | ||
4103 | fdput(cfile); | ||
4104 | out_put_eventfd: | ||
4105 | eventfd_ctx_put(event->eventfd); | ||
4106 | out_put_efile: | ||
4107 | fdput(efile); | ||
4108 | out_kfree: | ||
4109 | kfree(event); | ||
4110 | |||
4111 | return ret; | ||
4112 | } | ||
4113 | |||
4114 | static u64 cgroup_clone_children_read(struct cgroup_subsys_state *css, | 3873 | static u64 cgroup_clone_children_read(struct cgroup_subsys_state *css, |
4115 | struct cftype *cft) | 3874 | struct cftype *cft) |
4116 | { | 3875 | { |
@@ -4136,11 +3895,6 @@ static struct cftype cgroup_base_files[] = { | |||
4136 | .mode = S_IRUGO | S_IWUSR, | 3895 | .mode = S_IRUGO | S_IWUSR, |
4137 | }, | 3896 | }, |
4138 | { | 3897 | { |
4139 | .name = "cgroup.event_control", | ||
4140 | .write_string = cgroup_write_event_control, | ||
4141 | .mode = S_IWUGO, | ||
4142 | }, | ||
4143 | { | ||
4144 | .name = "cgroup.clone_children", | 3898 | .name = "cgroup.clone_children", |
4145 | .flags = CFTYPE_INSANE, | 3899 | .flags = CFTYPE_INSANE, |
4146 | .read_u64 = cgroup_clone_children_read, | 3900 | .read_u64 = cgroup_clone_children_read, |
@@ -4610,7 +4364,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4610 | __releases(&cgroup_mutex) __acquires(&cgroup_mutex) | 4364 | __releases(&cgroup_mutex) __acquires(&cgroup_mutex) |
4611 | { | 4365 | { |
4612 | struct dentry *d = cgrp->dentry; | 4366 | struct dentry *d = cgrp->dentry; |
4613 | struct cgroup_event *event, *tmp; | ||
4614 | struct cgroup_subsys *ss; | 4367 | struct cgroup_subsys *ss; |
4615 | struct cgroup *child; | 4368 | struct cgroup *child; |
4616 | bool empty; | 4369 | bool empty; |
@@ -4685,18 +4438,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4685 | dget(d); | 4438 | dget(d); |
4686 | cgroup_d_remove_dir(d); | 4439 | cgroup_d_remove_dir(d); |
4687 | 4440 | ||
4688 | /* | ||
4689 | * Unregister events and notify userspace. | ||
4690 | * Notify userspace about cgroup removing only after rmdir of cgroup | ||
4691 | * directory to avoid race between userspace and kernelspace. | ||
4692 | */ | ||
4693 | spin_lock(&cgrp->event_list_lock); | ||
4694 | list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) { | ||
4695 | list_del_init(&event->list); | ||
4696 | schedule_work(&event->remove); | ||
4697 | } | ||
4698 | spin_unlock(&cgrp->event_list_lock); | ||
4699 | |||
4700 | return 0; | 4441 | return 0; |
4701 | }; | 4442 | }; |
4702 | 4443 | ||