diff options
-rw-r--r-- | Documentation/controllers/memory.txt | 3 | ||||
-rw-r--r-- | mm/memcontrol.c | 48 |
2 files changed, 45 insertions, 6 deletions
diff --git a/Documentation/controllers/memory.txt b/Documentation/controllers/memory.txt index 866b9cd9a959..9b53d5827361 100644 --- a/Documentation/controllers/memory.txt +++ b/Documentation/controllers/memory.txt | |||
@@ -242,8 +242,7 @@ rmdir() if there are no tasks. | |||
242 | 1. Add support for accounting huge pages (as a separate controller) | 242 | 1. Add support for accounting huge pages (as a separate controller) |
243 | 2. Make per-cgroup scanner reclaim not-shared pages first | 243 | 2. Make per-cgroup scanner reclaim not-shared pages first |
244 | 3. Teach controller to account for shared-pages | 244 | 3. Teach controller to account for shared-pages |
245 | 4. Start reclamation when the limit is lowered | 245 | 4. Start reclamation in the background when the limit is |
246 | 5. Start reclamation in the background when the limit is | ||
247 | not yet hit but the usage is getting closer | 246 | not yet hit but the usage is getting closer |
248 | 247 | ||
249 | Summary | 248 | Summary |
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) |