diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 0c035647d36a..fba566c51322 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -812,6 +812,30 @@ int mem_cgroup_shrink_usage(struct mm_struct *mm, gfp_t gfp_mask) | |||
812 | return 0; | 812 | return 0; |
813 | } | 813 | } |
814 | 814 | ||
815 | int mem_cgroup_resize_limit(struct mem_cgroup *memcg, unsigned long long val) | ||
816 | { | ||
817 | |||
818 | int retry_count = MEM_CGROUP_RECLAIM_RETRIES; | ||
819 | int progress; | ||
820 | int ret = 0; | ||
821 | |||
822 | while (res_counter_set_limit(&memcg->res, val)) { | ||
823 | if (signal_pending(current)) { | ||
824 | ret = -EINTR; | ||
825 | break; | ||
826 | } | ||
827 | if (!retry_count) { | ||
828 | ret = -EBUSY; | ||
829 | break; | ||
830 | } | ||
831 | progress = try_to_free_mem_cgroup_pages(memcg, GFP_KERNEL); | ||
832 | if (!progress) | ||
833 | retry_count--; | ||
834 | } | ||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | |||
815 | /* | 839 | /* |
816 | * This routine traverse page_cgroup in given list and drop them all. | 840 | * This routine traverse page_cgroup in given list and drop them all. |
817 | * *And* this routine doesn't reclaim page itself, just removes page_cgroup. | 841 | * *And* this routine doesn't reclaim page itself, just removes page_cgroup. |
@@ -896,13 +920,29 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) | |||
896 | return res_counter_read_u64(&mem_cgroup_from_cont(cont)->res, | 920 | return res_counter_read_u64(&mem_cgroup_from_cont(cont)->res, |
897 | cft->private); | 921 | cft->private); |
898 | } | 922 | } |
899 | 923 | /* | |
924 | * The user of this function is... | ||
925 | * RES_LIMIT. | ||
926 | */ | ||
900 | static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft, | 927 | static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft, |
901 | const char *buffer) | 928 | const char *buffer) |
902 | { | 929 | { |
903 | return res_counter_write(&mem_cgroup_from_cont(cont)->res, | 930 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); |
904 | cft->private, buffer, | 931 | unsigned long long val; |
905 | res_counter_memparse_write_strategy); | 932 | int ret; |
933 | |||
934 | switch (cft->private) { | ||
935 | case RES_LIMIT: | ||
936 | /* This function does all necessary parse...reuse it */ | ||
937 | ret = res_counter_memparse_write_strategy(buffer, &val); | ||
938 | if (!ret) | ||
939 | ret = mem_cgroup_resize_limit(memcg, val); | ||
940 | break; | ||
941 | default: | ||
942 | ret = -EINVAL; /* should be BUG() ? */ | ||
943 | break; | ||
944 | } | ||
945 | return ret; | ||
906 | } | 946 | } |
907 | 947 | ||
908 | static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) | 948 | static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) |