diff options
author | Tejun Heo <tj@kernel.org> | 2013-11-22 18:20:43 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-11-22 18:20:43 -0500 |
commit | fba94807837850e211f8975e1970e23e7804ff4d (patch) | |
tree | c26b1b43027424574532e3fa74ed4656e445334a /mm/memcontrol.c | |
parent | b5557c4c3b1a38074d7001b87c2482eda3a0834a (diff) |
cgroup, memcg: move cgroup->event_list[_lock] and event callbacks into memcg
cgroup_event is being moved from cgroup core to memcg and the
implementation is already moved by the previous patch. This patch
moves the data fields and callbacks.
* cgroup->event_list[_lock] are moved to mem_cgroup.
* cftype->[un]register_event() are moved to cgroup_event. This makes
it impossible for individual cftype definitions to specify their
event callbacks. This is worked around by simply hard-coding
filename to event callback mapping in cgroup_write_event_control().
This is awkward and inflexible, which is actually desirable given
that we don't want to grow more usages of this feature.
* eventfd_ctx declaration is removed from cgroup.h, which makes
vmpressure.h miss eventfd_ctx declaration. Include eventfd.h from
vmpressure.h.
v2: Use file name from dentry instead of cftype. This will allow
removing all cftype handling in the function.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Balbir Singh <bsingharora@gmail.com>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 87 |
1 files changed, 60 insertions, 27 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d00368110b08..2fcacb18404b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -249,6 +249,22 @@ struct cgroup_event { | |||
249 | */ | 249 | */ |
250 | struct list_head list; | 250 | struct list_head list; |
251 | /* | 251 | /* |
252 | * register_event() callback will be used to add new userspace | ||
253 | * waiter for changes related to this event. Use eventfd_signal() | ||
254 | * on eventfd to send notification to userspace. | ||
255 | */ | ||
256 | int (*register_event)(struct cgroup_subsys_state *css, | ||
257 | struct cftype *cft, struct eventfd_ctx *eventfd, | ||
258 | const char *args); | ||
259 | /* | ||
260 | * unregister_event() callback will be called when userspace closes | ||
261 | * the eventfd or on cgroup removing. This callback must be set, | ||
262 | * if you want provide notification functionality. | ||
263 | */ | ||
264 | void (*unregister_event)(struct cgroup_subsys_state *css, | ||
265 | struct cftype *cft, | ||
266 | struct eventfd_ctx *eventfd); | ||
267 | /* | ||
252 | * All fields below needed to unregister event when | 268 | * All fields below needed to unregister event when |
253 | * userspace closes eventfd. | 269 | * userspace closes eventfd. |
254 | */ | 270 | */ |
@@ -362,6 +378,10 @@ struct mem_cgroup { | |||
362 | atomic_t numainfo_updating; | 378 | atomic_t numainfo_updating; |
363 | #endif | 379 | #endif |
364 | 380 | ||
381 | /* List of events which userspace want to receive */ | ||
382 | struct list_head event_list; | ||
383 | spinlock_t event_list_lock; | ||
384 | |||
365 | struct mem_cgroup_per_node *nodeinfo[0]; | 385 | struct mem_cgroup_per_node *nodeinfo[0]; |
366 | /* WARNING: nodeinfo must be the last member here */ | 386 | /* WARNING: nodeinfo must be the last member here */ |
367 | }; | 387 | }; |
@@ -5992,7 +6012,7 @@ static void cgroup_event_remove(struct work_struct *work) | |||
5992 | 6012 | ||
5993 | remove_wait_queue(event->wqh, &event->wait); | 6013 | remove_wait_queue(event->wqh, &event->wait); |
5994 | 6014 | ||
5995 | event->cft->unregister_event(css, event->cft, event->eventfd); | 6015 | event->unregister_event(css, event->cft, event->eventfd); |
5996 | 6016 | ||
5997 | /* Notify userspace the event is going away. */ | 6017 | /* Notify userspace the event is going away. */ |
5998 | eventfd_signal(event->eventfd, 1); | 6018 | eventfd_signal(event->eventfd, 1); |
@@ -6012,7 +6032,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, | |||
6012 | { | 6032 | { |
6013 | struct cgroup_event *event = container_of(wait, | 6033 | struct cgroup_event *event = container_of(wait, |
6014 | struct cgroup_event, wait); | 6034 | struct cgroup_event, wait); |
6015 | struct cgroup *cgrp = event->css->cgroup; | 6035 | struct mem_cgroup *memcg = mem_cgroup_from_css(event->css); |
6016 | unsigned long flags = (unsigned long)key; | 6036 | unsigned long flags = (unsigned long)key; |
6017 | 6037 | ||
6018 | if (flags & POLLHUP) { | 6038 | if (flags & POLLHUP) { |
@@ -6025,7 +6045,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, | |||
6025 | * side will require wqh->lock via remove_wait_queue(), | 6045 | * side will require wqh->lock via remove_wait_queue(), |
6026 | * which we hold. | 6046 | * which we hold. |
6027 | */ | 6047 | */ |
6028 | spin_lock(&cgrp->event_list_lock); | 6048 | spin_lock(&memcg->event_list_lock); |
6029 | if (!list_empty(&event->list)) { | 6049 | if (!list_empty(&event->list)) { |
6030 | list_del_init(&event->list); | 6050 | list_del_init(&event->list); |
6031 | /* | 6051 | /* |
@@ -6034,7 +6054,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, | |||
6034 | */ | 6054 | */ |
6035 | schedule_work(&event->remove); | 6055 | schedule_work(&event->remove); |
6036 | } | 6056 | } |
6037 | spin_unlock(&cgrp->event_list_lock); | 6057 | spin_unlock(&memcg->event_list_lock); |
6038 | } | 6058 | } |
6039 | 6059 | ||
6040 | return 0; | 6060 | return 0; |
@@ -6059,12 +6079,13 @@ static void cgroup_event_ptable_queue_proc(struct file *file, | |||
6059 | static int cgroup_write_event_control(struct cgroup_subsys_state *css, | 6079 | static int cgroup_write_event_control(struct cgroup_subsys_state *css, |
6060 | struct cftype *cft, const char *buffer) | 6080 | struct cftype *cft, const char *buffer) |
6061 | { | 6081 | { |
6062 | struct cgroup *cgrp = css->cgroup; | 6082 | struct mem_cgroup *memcg = mem_cgroup_from_css(css); |
6063 | struct cgroup_event *event; | 6083 | struct cgroup_event *event; |
6064 | struct cgroup_subsys_state *cfile_css; | 6084 | struct cgroup_subsys_state *cfile_css; |
6065 | unsigned int efd, cfd; | 6085 | unsigned int efd, cfd; |
6066 | struct fd efile; | 6086 | struct fd efile; |
6067 | struct fd cfile; | 6087 | struct fd cfile; |
6088 | const char *name; | ||
6068 | char *endp; | 6089 | char *endp; |
6069 | int ret; | 6090 | int ret; |
6070 | 6091 | ||
@@ -6119,6 +6140,31 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, | |||
6119 | } | 6140 | } |
6120 | 6141 | ||
6121 | /* | 6142 | /* |
6143 | * Determine the event callbacks and set them in @event. This used | ||
6144 | * to be done via struct cftype but cgroup core no longer knows | ||
6145 | * about these events. The following is crude but the whole thing | ||
6146 | * is for compatibility anyway. | ||
6147 | */ | ||
6148 | name = cfile.file->f_dentry->d_name.name; | ||
6149 | |||
6150 | if (!strcmp(name, "memory.usage_in_bytes")) { | ||
6151 | event->register_event = mem_cgroup_usage_register_event; | ||
6152 | event->unregister_event = mem_cgroup_usage_unregister_event; | ||
6153 | } else if (!strcmp(name, "memory.oom_control")) { | ||
6154 | event->register_event = mem_cgroup_oom_register_event; | ||
6155 | event->unregister_event = mem_cgroup_oom_unregister_event; | ||
6156 | } else if (!strcmp(name, "memory.pressure_level")) { | ||
6157 | event->register_event = vmpressure_register_event; | ||
6158 | event->unregister_event = vmpressure_unregister_event; | ||
6159 | } else if (!strcmp(name, "memory.memsw.usage_in_bytes")) { | ||
6160 | event->register_event = mem_cgroup_usage_register_event; | ||
6161 | event->unregister_event = mem_cgroup_usage_unregister_event; | ||
6162 | } else { | ||
6163 | ret = -EINVAL; | ||
6164 | goto out_put_cfile; | ||
6165 | } | ||
6166 | |||
6167 | /* | ||
6122 | * Verify @cfile should belong to @css. Also, remaining events are | 6168 | * Verify @cfile should belong to @css. Also, remaining events are |
6123 | * automatically removed on cgroup destruction but the removal is | 6169 | * automatically removed on cgroup destruction but the removal is |
6124 | * asynchronous, so take an extra ref on @css. | 6170 | * asynchronous, so take an extra ref on @css. |
@@ -6135,21 +6181,15 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, | |||
6135 | if (ret) | 6181 | if (ret) |
6136 | goto out_put_cfile; | 6182 | goto out_put_cfile; |
6137 | 6183 | ||
6138 | if (!event->cft->register_event || !event->cft->unregister_event) { | 6184 | ret = event->register_event(css, event->cft, event->eventfd, buffer); |
6139 | ret = -EINVAL; | ||
6140 | goto out_put_css; | ||
6141 | } | ||
6142 | |||
6143 | ret = event->cft->register_event(css, event->cft, | ||
6144 | event->eventfd, buffer); | ||
6145 | if (ret) | 6185 | if (ret) |
6146 | goto out_put_css; | 6186 | goto out_put_css; |
6147 | 6187 | ||
6148 | efile.file->f_op->poll(efile.file, &event->pt); | 6188 | efile.file->f_op->poll(efile.file, &event->pt); |
6149 | 6189 | ||
6150 | spin_lock(&cgrp->event_list_lock); | 6190 | spin_lock(&memcg->event_list_lock); |
6151 | list_add(&event->list, &cgrp->event_list); | 6191 | list_add(&event->list, &memcg->event_list); |
6152 | spin_unlock(&cgrp->event_list_lock); | 6192 | spin_unlock(&memcg->event_list_lock); |
6153 | 6193 | ||
6154 | fdput(cfile); | 6194 | fdput(cfile); |
6155 | fdput(efile); | 6195 | fdput(efile); |
@@ -6175,8 +6215,6 @@ static struct cftype mem_cgroup_files[] = { | |||
6175 | .name = "usage_in_bytes", | 6215 | .name = "usage_in_bytes", |
6176 | .private = MEMFILE_PRIVATE(_MEM, RES_USAGE), | 6216 | .private = MEMFILE_PRIVATE(_MEM, RES_USAGE), |
6177 | .read = mem_cgroup_read, | 6217 | .read = mem_cgroup_read, |
6178 | .register_event = mem_cgroup_usage_register_event, | ||
6179 | .unregister_event = mem_cgroup_usage_unregister_event, | ||
6180 | }, | 6218 | }, |
6181 | { | 6219 | { |
6182 | .name = "max_usage_in_bytes", | 6220 | .name = "max_usage_in_bytes", |
@@ -6236,14 +6274,10 @@ static struct cftype mem_cgroup_files[] = { | |||
6236 | .name = "oom_control", | 6274 | .name = "oom_control", |
6237 | .read_map = mem_cgroup_oom_control_read, | 6275 | .read_map = mem_cgroup_oom_control_read, |
6238 | .write_u64 = mem_cgroup_oom_control_write, | 6276 | .write_u64 = mem_cgroup_oom_control_write, |
6239 | .register_event = mem_cgroup_oom_register_event, | ||
6240 | .unregister_event = mem_cgroup_oom_unregister_event, | ||
6241 | .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL), | 6277 | .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL), |
6242 | }, | 6278 | }, |
6243 | { | 6279 | { |
6244 | .name = "pressure_level", | 6280 | .name = "pressure_level", |
6245 | .register_event = vmpressure_register_event, | ||
6246 | .unregister_event = vmpressure_unregister_event, | ||
6247 | }, | 6281 | }, |
6248 | #ifdef CONFIG_NUMA | 6282 | #ifdef CONFIG_NUMA |
6249 | { | 6283 | { |
@@ -6291,8 +6325,6 @@ static struct cftype memsw_cgroup_files[] = { | |||
6291 | .name = "memsw.usage_in_bytes", | 6325 | .name = "memsw.usage_in_bytes", |
6292 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), | 6326 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), |
6293 | .read = mem_cgroup_read, | 6327 | .read = mem_cgroup_read, |
6294 | .register_event = mem_cgroup_usage_register_event, | ||
6295 | .unregister_event = mem_cgroup_usage_unregister_event, | ||
6296 | }, | 6328 | }, |
6297 | { | 6329 | { |
6298 | .name = "memsw.max_usage_in_bytes", | 6330 | .name = "memsw.max_usage_in_bytes", |
@@ -6483,6 +6515,8 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) | |||
6483 | mutex_init(&memcg->thresholds_lock); | 6515 | mutex_init(&memcg->thresholds_lock); |
6484 | spin_lock_init(&memcg->move_lock); | 6516 | spin_lock_init(&memcg->move_lock); |
6485 | vmpressure_init(&memcg->vmpressure); | 6517 | vmpressure_init(&memcg->vmpressure); |
6518 | INIT_LIST_HEAD(&memcg->event_list); | ||
6519 | spin_lock_init(&memcg->event_list_lock); | ||
6486 | 6520 | ||
6487 | return &memcg->css; | 6521 | return &memcg->css; |
6488 | 6522 | ||
@@ -6555,7 +6589,6 @@ static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg) | |||
6555 | static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) | 6589 | static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) |
6556 | { | 6590 | { |
6557 | struct mem_cgroup *memcg = mem_cgroup_from_css(css); | 6591 | struct mem_cgroup *memcg = mem_cgroup_from_css(css); |
6558 | struct cgroup *cgrp = css->cgroup; | ||
6559 | struct cgroup_event *event, *tmp; | 6592 | struct cgroup_event *event, *tmp; |
6560 | 6593 | ||
6561 | /* | 6594 | /* |
@@ -6563,12 +6596,12 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) | |||
6563 | * Notify userspace about cgroup removing only after rmdir of cgroup | 6596 | * Notify userspace about cgroup removing only after rmdir of cgroup |
6564 | * directory to avoid race between userspace and kernelspace. | 6597 | * directory to avoid race between userspace and kernelspace. |
6565 | */ | 6598 | */ |
6566 | spin_lock(&cgrp->event_list_lock); | 6599 | spin_lock(&memcg->event_list_lock); |
6567 | list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) { | 6600 | list_for_each_entry_safe(event, tmp, &memcg->event_list, list) { |
6568 | list_del_init(&event->list); | 6601 | list_del_init(&event->list); |
6569 | schedule_work(&event->remove); | 6602 | schedule_work(&event->remove); |
6570 | } | 6603 | } |
6571 | spin_unlock(&cgrp->event_list_lock); | 6604 | spin_unlock(&memcg->event_list_lock); |
6572 | 6605 | ||
6573 | kmem_cgroup_css_offline(memcg); | 6606 | kmem_cgroup_css_offline(memcg); |
6574 | 6607 | ||