diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-22 20:40:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-22 20:40:19 -0400 |
commit | 88d6ae8dc33af12fe1c7941b1fae2767374046fd (patch) | |
tree | 8f17415c0722b0a4d7511ac170cfb4e3802e1ad2 /mm | |
parent | f5c101892fbd3d2f6d2729bc7eb7b3f6c31dbddd (diff) | |
parent | 0d4dde1ac9a5af74ac76c6ab90557d1ae7b8f5d8 (diff) |
Merge branch 'for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup updates from Tejun Heo:
"cgroup file type addition / removal is updated so that file types are
added and removed instead of individual files so that dynamic file
type addition / removal can be implemented by cgroup and used by
controllers. blkio controller changes which will come through block
tree are dependent on this. Other changes include res_counter cleanup
and disallowing kthread / PF_THREAD_BOUND threads to be attached to
non-root cgroups.
There's a reported bug with the file type addition / removal handling
which can lead to oops on cgroup umount. The issue is being looked
into. It shouldn't cause problems for most setups and isn't a
security concern."
Fix up trivial conflict in Documentation/feature-removal-schedule.txt
* 'for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: (21 commits)
res_counter: Account max_usage when calling res_counter_charge_nofail()
res_counter: Merge res_counter_charge and res_counter_charge_nofail
cgroups: disallow attaching kthreadd or PF_THREAD_BOUND threads
cgroup: remove cgroup_subsys->populate()
cgroup: get rid of populate for memcg
cgroup: pass struct mem_cgroup instead of struct cgroup to socket memcg
cgroup: make css->refcnt clearing on cgroup removal optional
cgroup: use negative bias on css->refcnt to block css_tryget()
cgroup: implement cgroup_rm_cftypes()
cgroup: introduce struct cfent
cgroup: relocate __d_cgrp() and __d_cft()
cgroup: remove cgroup_add_file[s]()
cgroup: convert memcg controller to the new cftype interface
memcg: always create memsw files if CONFIG_CGROUP_MEM_RES_CTLR_SWAP
cgroup: convert all non-memcg controllers to the new cftype interface
cgroup: relocate cftype and cgroup_subsys definitions in controllers
cgroup: merge cft_release_agent cftype array into the base files array
cgroup: implement cgroup_add_cftypes() and friends
cgroup: build list of all cgroups under a given cgroupfs_root
cgroup: move cgroup_clear_directory() call out of cgroup_populate_dir()
...
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memcontrol.c | 115 |
1 files changed, 52 insertions, 63 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7685d4a0b3ce..f342778a0c0a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -3873,14 +3873,21 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap) | |||
3873 | return val << PAGE_SHIFT; | 3873 | return val << PAGE_SHIFT; |
3874 | } | 3874 | } |
3875 | 3875 | ||
3876 | static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) | 3876 | static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft, |
3877 | struct file *file, char __user *buf, | ||
3878 | size_t nbytes, loff_t *ppos) | ||
3877 | { | 3879 | { |
3878 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); | 3880 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); |
3881 | char str[64]; | ||
3879 | u64 val; | 3882 | u64 val; |
3880 | int type, name; | 3883 | int type, name, len; |
3881 | 3884 | ||
3882 | type = MEMFILE_TYPE(cft->private); | 3885 | type = MEMFILE_TYPE(cft->private); |
3883 | name = MEMFILE_ATTR(cft->private); | 3886 | name = MEMFILE_ATTR(cft->private); |
3887 | |||
3888 | if (!do_swap_account && type == _MEMSWAP) | ||
3889 | return -EOPNOTSUPP; | ||
3890 | |||
3884 | switch (type) { | 3891 | switch (type) { |
3885 | case _MEM: | 3892 | case _MEM: |
3886 | if (name == RES_USAGE) | 3893 | if (name == RES_USAGE) |
@@ -3897,7 +3904,9 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) | |||
3897 | default: | 3904 | default: |
3898 | BUG(); | 3905 | BUG(); |
3899 | } | 3906 | } |
3900 | return val; | 3907 | |
3908 | len = scnprintf(str, sizeof(str), "%llu\n", (unsigned long long)val); | ||
3909 | return simple_read_from_buffer(buf, nbytes, ppos, str, len); | ||
3901 | } | 3910 | } |
3902 | /* | 3911 | /* |
3903 | * The user of this function is... | 3912 | * The user of this function is... |
@@ -3913,6 +3922,10 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft, | |||
3913 | 3922 | ||
3914 | type = MEMFILE_TYPE(cft->private); | 3923 | type = MEMFILE_TYPE(cft->private); |
3915 | name = MEMFILE_ATTR(cft->private); | 3924 | name = MEMFILE_ATTR(cft->private); |
3925 | |||
3926 | if (!do_swap_account && type == _MEMSWAP) | ||
3927 | return -EOPNOTSUPP; | ||
3928 | |||
3916 | switch (name) { | 3929 | switch (name) { |
3917 | case RES_LIMIT: | 3930 | case RES_LIMIT: |
3918 | if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */ | 3931 | if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */ |
@@ -3978,12 +3991,15 @@ out: | |||
3978 | 3991 | ||
3979 | static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) | 3992 | static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) |
3980 | { | 3993 | { |
3981 | struct mem_cgroup *memcg; | 3994 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); |
3982 | int type, name; | 3995 | int type, name; |
3983 | 3996 | ||
3984 | memcg = mem_cgroup_from_cont(cont); | ||
3985 | type = MEMFILE_TYPE(event); | 3997 | type = MEMFILE_TYPE(event); |
3986 | name = MEMFILE_ATTR(event); | 3998 | name = MEMFILE_ATTR(event); |
3999 | |||
4000 | if (!do_swap_account && type == _MEMSWAP) | ||
4001 | return -EOPNOTSUPP; | ||
4002 | |||
3987 | switch (name) { | 4003 | switch (name) { |
3988 | case RES_MAX_USAGE: | 4004 | case RES_MAX_USAGE: |
3989 | if (type == _MEM) | 4005 | if (type == _MEM) |
@@ -4624,29 +4640,22 @@ static int mem_control_numa_stat_open(struct inode *unused, struct file *file) | |||
4624 | #endif /* CONFIG_NUMA */ | 4640 | #endif /* CONFIG_NUMA */ |
4625 | 4641 | ||
4626 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM | 4642 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM |
4627 | static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) | 4643 | static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss) |
4628 | { | 4644 | { |
4629 | /* | 4645 | return mem_cgroup_sockets_init(memcg, ss); |
4630 | * Part of this would be better living in a separate allocation | ||
4631 | * function, leaving us with just the cgroup tree population work. | ||
4632 | * We, however, depend on state such as network's proto_list that | ||
4633 | * is only initialized after cgroup creation. I found the less | ||
4634 | * cumbersome way to deal with it to defer it all to populate time | ||
4635 | */ | ||
4636 | return mem_cgroup_sockets_init(cont, ss); | ||
4637 | }; | 4646 | }; |
4638 | 4647 | ||
4639 | static void kmem_cgroup_destroy(struct cgroup *cont) | 4648 | static void kmem_cgroup_destroy(struct mem_cgroup *memcg) |
4640 | { | 4649 | { |
4641 | mem_cgroup_sockets_destroy(cont); | 4650 | mem_cgroup_sockets_destroy(memcg); |
4642 | } | 4651 | } |
4643 | #else | 4652 | #else |
4644 | static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) | 4653 | static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss) |
4645 | { | 4654 | { |
4646 | return 0; | 4655 | return 0; |
4647 | } | 4656 | } |
4648 | 4657 | ||
4649 | static void kmem_cgroup_destroy(struct cgroup *cont) | 4658 | static void kmem_cgroup_destroy(struct mem_cgroup *memcg) |
4650 | { | 4659 | { |
4651 | } | 4660 | } |
4652 | #endif | 4661 | #endif |
@@ -4655,7 +4664,7 @@ static struct cftype mem_cgroup_files[] = { | |||
4655 | { | 4664 | { |
4656 | .name = "usage_in_bytes", | 4665 | .name = "usage_in_bytes", |
4657 | .private = MEMFILE_PRIVATE(_MEM, RES_USAGE), | 4666 | .private = MEMFILE_PRIVATE(_MEM, RES_USAGE), |
4658 | .read_u64 = mem_cgroup_read, | 4667 | .read = mem_cgroup_read, |
4659 | .register_event = mem_cgroup_usage_register_event, | 4668 | .register_event = mem_cgroup_usage_register_event, |
4660 | .unregister_event = mem_cgroup_usage_unregister_event, | 4669 | .unregister_event = mem_cgroup_usage_unregister_event, |
4661 | }, | 4670 | }, |
@@ -4663,25 +4672,25 @@ static struct cftype mem_cgroup_files[] = { | |||
4663 | .name = "max_usage_in_bytes", | 4672 | .name = "max_usage_in_bytes", |
4664 | .private = MEMFILE_PRIVATE(_MEM, RES_MAX_USAGE), | 4673 | .private = MEMFILE_PRIVATE(_MEM, RES_MAX_USAGE), |
4665 | .trigger = mem_cgroup_reset, | 4674 | .trigger = mem_cgroup_reset, |
4666 | .read_u64 = mem_cgroup_read, | 4675 | .read = mem_cgroup_read, |
4667 | }, | 4676 | }, |
4668 | { | 4677 | { |
4669 | .name = "limit_in_bytes", | 4678 | .name = "limit_in_bytes", |
4670 | .private = MEMFILE_PRIVATE(_MEM, RES_LIMIT), | 4679 | .private = MEMFILE_PRIVATE(_MEM, RES_LIMIT), |
4671 | .write_string = mem_cgroup_write, | 4680 | .write_string = mem_cgroup_write, |
4672 | .read_u64 = mem_cgroup_read, | 4681 | .read = mem_cgroup_read, |
4673 | }, | 4682 | }, |
4674 | { | 4683 | { |
4675 | .name = "soft_limit_in_bytes", | 4684 | .name = "soft_limit_in_bytes", |
4676 | .private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT), | 4685 | .private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT), |
4677 | .write_string = mem_cgroup_write, | 4686 | .write_string = mem_cgroup_write, |
4678 | .read_u64 = mem_cgroup_read, | 4687 | .read = mem_cgroup_read, |
4679 | }, | 4688 | }, |
4680 | { | 4689 | { |
4681 | .name = "failcnt", | 4690 | .name = "failcnt", |
4682 | .private = MEMFILE_PRIVATE(_MEM, RES_FAILCNT), | 4691 | .private = MEMFILE_PRIVATE(_MEM, RES_FAILCNT), |
4683 | .trigger = mem_cgroup_reset, | 4692 | .trigger = mem_cgroup_reset, |
4684 | .read_u64 = mem_cgroup_read, | 4693 | .read = mem_cgroup_read, |
4685 | }, | 4694 | }, |
4686 | { | 4695 | { |
4687 | .name = "stat", | 4696 | .name = "stat", |
@@ -4721,14 +4730,11 @@ static struct cftype mem_cgroup_files[] = { | |||
4721 | .mode = S_IRUGO, | 4730 | .mode = S_IRUGO, |
4722 | }, | 4731 | }, |
4723 | #endif | 4732 | #endif |
4724 | }; | ||
4725 | |||
4726 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP | 4733 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP |
4727 | static struct cftype memsw_cgroup_files[] = { | ||
4728 | { | 4734 | { |
4729 | .name = "memsw.usage_in_bytes", | 4735 | .name = "memsw.usage_in_bytes", |
4730 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), | 4736 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), |
4731 | .read_u64 = mem_cgroup_read, | 4737 | .read = mem_cgroup_read, |
4732 | .register_event = mem_cgroup_usage_register_event, | 4738 | .register_event = mem_cgroup_usage_register_event, |
4733 | .unregister_event = mem_cgroup_usage_unregister_event, | 4739 | .unregister_event = mem_cgroup_usage_unregister_event, |
4734 | }, | 4740 | }, |
@@ -4736,35 +4742,23 @@ static struct cftype memsw_cgroup_files[] = { | |||
4736 | .name = "memsw.max_usage_in_bytes", | 4742 | .name = "memsw.max_usage_in_bytes", |
4737 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE), | 4743 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE), |
4738 | .trigger = mem_cgroup_reset, | 4744 | .trigger = mem_cgroup_reset, |
4739 | .read_u64 = mem_cgroup_read, | 4745 | .read = mem_cgroup_read, |
4740 | }, | 4746 | }, |
4741 | { | 4747 | { |
4742 | .name = "memsw.limit_in_bytes", | 4748 | .name = "memsw.limit_in_bytes", |
4743 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT), | 4749 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT), |
4744 | .write_string = mem_cgroup_write, | 4750 | .write_string = mem_cgroup_write, |
4745 | .read_u64 = mem_cgroup_read, | 4751 | .read = mem_cgroup_read, |
4746 | }, | 4752 | }, |
4747 | { | 4753 | { |
4748 | .name = "memsw.failcnt", | 4754 | .name = "memsw.failcnt", |
4749 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT), | 4755 | .private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT), |
4750 | .trigger = mem_cgroup_reset, | 4756 | .trigger = mem_cgroup_reset, |
4751 | .read_u64 = mem_cgroup_read, | 4757 | .read = mem_cgroup_read, |
4752 | }, | 4758 | }, |
4753 | }; | ||
4754 | |||
4755 | static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss) | ||
4756 | { | ||
4757 | if (!do_swap_account) | ||
4758 | return 0; | ||
4759 | return cgroup_add_files(cont, ss, memsw_cgroup_files, | ||
4760 | ARRAY_SIZE(memsw_cgroup_files)); | ||
4761 | }; | ||
4762 | #else | ||
4763 | static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss) | ||
4764 | { | ||
4765 | return 0; | ||
4766 | } | ||
4767 | #endif | 4759 | #endif |
4760 | { }, /* terminate */ | ||
4761 | }; | ||
4768 | 4762 | ||
4769 | static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) | 4763 | static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) |
4770 | { | 4764 | { |
@@ -5016,6 +5010,17 @@ mem_cgroup_create(struct cgroup *cont) | |||
5016 | memcg->move_charge_at_immigrate = 0; | 5010 | memcg->move_charge_at_immigrate = 0; |
5017 | mutex_init(&memcg->thresholds_lock); | 5011 | mutex_init(&memcg->thresholds_lock); |
5018 | spin_lock_init(&memcg->move_lock); | 5012 | spin_lock_init(&memcg->move_lock); |
5013 | |||
5014 | error = memcg_init_kmem(memcg, &mem_cgroup_subsys); | ||
5015 | if (error) { | ||
5016 | /* | ||
5017 | * We call put now because our (and parent's) refcnts | ||
5018 | * are already in place. mem_cgroup_put() will internally | ||
5019 | * call __mem_cgroup_free, so return directly | ||
5020 | */ | ||
5021 | mem_cgroup_put(memcg); | ||
5022 | return ERR_PTR(error); | ||
5023 | } | ||
5019 | return &memcg->css; | 5024 | return &memcg->css; |
5020 | free_out: | 5025 | free_out: |
5021 | __mem_cgroup_free(memcg); | 5026 | __mem_cgroup_free(memcg); |
@@ -5033,28 +5038,11 @@ static void mem_cgroup_destroy(struct cgroup *cont) | |||
5033 | { | 5038 | { |
5034 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); | 5039 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); |
5035 | 5040 | ||
5036 | kmem_cgroup_destroy(cont); | 5041 | kmem_cgroup_destroy(memcg); |
5037 | 5042 | ||
5038 | mem_cgroup_put(memcg); | 5043 | mem_cgroup_put(memcg); |
5039 | } | 5044 | } |
5040 | 5045 | ||
5041 | static int mem_cgroup_populate(struct cgroup_subsys *ss, | ||
5042 | struct cgroup *cont) | ||
5043 | { | ||
5044 | int ret; | ||
5045 | |||
5046 | ret = cgroup_add_files(cont, ss, mem_cgroup_files, | ||
5047 | ARRAY_SIZE(mem_cgroup_files)); | ||
5048 | |||
5049 | if (!ret) | ||
5050 | ret = register_memsw_files(cont, ss); | ||
5051 | |||
5052 | if (!ret) | ||
5053 | ret = register_kmem_files(cont, ss); | ||
5054 | |||
5055 | return ret; | ||
5056 | } | ||
5057 | |||
5058 | #ifdef CONFIG_MMU | 5046 | #ifdef CONFIG_MMU |
5059 | /* Handlers for move charge at task migration. */ | 5047 | /* Handlers for move charge at task migration. */ |
5060 | #define PRECHARGE_COUNT_AT_ONCE 256 | 5048 | #define PRECHARGE_COUNT_AT_ONCE 256 |
@@ -5638,12 +5626,13 @@ struct cgroup_subsys mem_cgroup_subsys = { | |||
5638 | .create = mem_cgroup_create, | 5626 | .create = mem_cgroup_create, |
5639 | .pre_destroy = mem_cgroup_pre_destroy, | 5627 | .pre_destroy = mem_cgroup_pre_destroy, |
5640 | .destroy = mem_cgroup_destroy, | 5628 | .destroy = mem_cgroup_destroy, |
5641 | .populate = mem_cgroup_populate, | ||
5642 | .can_attach = mem_cgroup_can_attach, | 5629 | .can_attach = mem_cgroup_can_attach, |
5643 | .cancel_attach = mem_cgroup_cancel_attach, | 5630 | .cancel_attach = mem_cgroup_cancel_attach, |
5644 | .attach = mem_cgroup_move_task, | 5631 | .attach = mem_cgroup_move_task, |
5632 | .base_cftypes = mem_cgroup_files, | ||
5645 | .early_init = 0, | 5633 | .early_init = 0, |
5646 | .use_id = 1, | 5634 | .use_id = 1, |
5635 | .__DEPRECATED_clear_css_refs = true, | ||
5647 | }; | 5636 | }; |
5648 | 5637 | ||
5649 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP | 5638 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP |