aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2009-09-08 20:55:21 -0400
committerDan Williams <dan.j.williams@intel.com>2009-09-08 20:55:21 -0400
commitbbb20089a3275a19e475dbc21320c3742e3ca423 (patch)
tree216fdc1cbef450ca688135c5b8969169482d9a48 /mm/memcontrol.c
parent3e48e656903e9fd8bc805c6a2c4264d7808d315b (diff)
parent657a77fa7284d8ae28dfa48f1dc5d919bf5b2843 (diff)
Merge branch 'dmaengine' into async-tx-next
Conflicts: crypto/async_tx/async_xor.c drivers/dma/ioat/dma_v2.h drivers/dma/ioat/pci.c drivers/md/raid5.c
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c137
1 files changed, 123 insertions, 14 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 78eb8552818b..e2fa20dadf40 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -45,7 +45,7 @@ struct cgroup_subsys mem_cgroup_subsys __read_mostly;
45#define MEM_CGROUP_RECLAIM_RETRIES 5 45#define MEM_CGROUP_RECLAIM_RETRIES 5
46 46
47#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP 47#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
48/* Turned on only when memory cgroup is enabled && really_do_swap_account = 0 */ 48/* Turned on only when memory cgroup is enabled && really_do_swap_account = 1 */
49int do_swap_account __read_mostly; 49int do_swap_account __read_mostly;
50static int really_do_swap_account __initdata = 1; /* for remember boot option*/ 50static int really_do_swap_account __initdata = 1; /* for remember boot option*/
51#else 51#else
@@ -62,7 +62,8 @@ enum mem_cgroup_stat_index {
62 * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss. 62 * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss.
63 */ 63 */
64 MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ 64 MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */
65 MEM_CGROUP_STAT_RSS, /* # of pages charged as rss */ 65 MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */
66 MEM_CGROUP_STAT_MAPPED_FILE, /* # of pages charged as file rss */
66 MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */ 67 MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */
67 MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */ 68 MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */
68 69
@@ -176,6 +177,9 @@ struct mem_cgroup {
176 177
177 unsigned int swappiness; 178 unsigned int swappiness;
178 179
180 /* set when res.limit == memsw.limit */
181 bool memsw_is_minimum;
182
179 /* 183 /*
180 * statistics. This must be placed at the end of memcg. 184 * statistics. This must be placed at the end of memcg.
181 */ 185 */
@@ -188,6 +192,7 @@ enum charge_type {
188 MEM_CGROUP_CHARGE_TYPE_SHMEM, /* used by page migration of shmem */ 192 MEM_CGROUP_CHARGE_TYPE_SHMEM, /* used by page migration of shmem */
189 MEM_CGROUP_CHARGE_TYPE_FORCE, /* used by force_empty */ 193 MEM_CGROUP_CHARGE_TYPE_FORCE, /* used by force_empty */
190 MEM_CGROUP_CHARGE_TYPE_SWAPOUT, /* for accounting swapcache */ 194 MEM_CGROUP_CHARGE_TYPE_SWAPOUT, /* for accounting swapcache */
195 MEM_CGROUP_CHARGE_TYPE_DROP, /* a page was unused swap cache */
191 NR_CHARGE_TYPE, 196 NR_CHARGE_TYPE,
192}; 197};
193 198
@@ -570,6 +575,17 @@ int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg)
570 return 0; 575 return 0;
571} 576}
572 577
578int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
579{
580 unsigned long active;
581 unsigned long inactive;
582
583 inactive = mem_cgroup_get_local_zonestat(memcg, LRU_INACTIVE_FILE);
584 active = mem_cgroup_get_local_zonestat(memcg, LRU_ACTIVE_FILE);
585
586 return (active > inactive);
587}
588
573unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg, 589unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
574 struct zone *zone, 590 struct zone *zone,
575 enum lru_list lru) 591 enum lru_list lru)
@@ -633,6 +649,7 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
633 int zid = zone_idx(z); 649 int zid = zone_idx(z);
634 struct mem_cgroup_per_zone *mz; 650 struct mem_cgroup_per_zone *mz;
635 int lru = LRU_FILE * !!file + !!active; 651 int lru = LRU_FILE * !!file + !!active;
652 int ret;
636 653
637 BUG_ON(!mem_cont); 654 BUG_ON(!mem_cont);
638 mz = mem_cgroup_zoneinfo(mem_cont, nid, zid); 655 mz = mem_cgroup_zoneinfo(mem_cont, nid, zid);
@@ -650,9 +667,19 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
650 continue; 667 continue;
651 668
652 scan++; 669 scan++;
653 if (__isolate_lru_page(page, mode, file) == 0) { 670 ret = __isolate_lru_page(page, mode, file);
671 switch (ret) {
672 case 0:
654 list_move(&page->lru, dst); 673 list_move(&page->lru, dst);
674 mem_cgroup_del_lru(page);
655 nr_taken++; 675 nr_taken++;
676 break;
677 case -EBUSY:
678 /* we don't affect global LRU but rotate in our LRU */
679 mem_cgroup_rotate_lru_list(page, page_lru(page));
680 break;
681 default:
682 break;
656 } 683 }
657 } 684 }
658 685
@@ -834,6 +861,10 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
834 int ret, total = 0; 861 int ret, total = 0;
835 int loop = 0; 862 int loop = 0;
836 863
864 /* If memsw_is_minimum==1, swap-out is of-no-use. */
865 if (root_mem->memsw_is_minimum)
866 noswap = true;
867
837 while (loop < 2) { 868 while (loop < 2) {
838 victim = mem_cgroup_select_victim(root_mem); 869 victim = mem_cgroup_select_victim(root_mem);
839 if (victim == root_mem) 870 if (victim == root_mem)
@@ -889,6 +920,44 @@ static void record_last_oom(struct mem_cgroup *mem)
889 mem_cgroup_walk_tree(mem, NULL, record_last_oom_cb); 920 mem_cgroup_walk_tree(mem, NULL, record_last_oom_cb);
890} 921}
891 922
923/*
924 * Currently used to update mapped file statistics, but the routine can be
925 * generalized to update other statistics as well.
926 */
927void mem_cgroup_update_mapped_file_stat(struct page *page, int val)
928{
929 struct mem_cgroup *mem;
930 struct mem_cgroup_stat *stat;
931 struct mem_cgroup_stat_cpu *cpustat;
932 int cpu;
933 struct page_cgroup *pc;
934
935 if (!page_is_file_cache(page))
936 return;
937
938 pc = lookup_page_cgroup(page);
939 if (unlikely(!pc))
940 return;
941
942 lock_page_cgroup(pc);
943 mem = pc->mem_cgroup;
944 if (!mem)
945 goto done;
946
947 if (!PageCgroupUsed(pc))
948 goto done;
949
950 /*
951 * Preemption is already disabled, we don't need get_cpu()
952 */
953 cpu = smp_processor_id();
954 stat = &mem->stat;
955 cpustat = &stat->cpustat[cpu];
956
957 __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE, val);
958done:
959 unlock_page_cgroup(pc);
960}
892 961
893/* 962/*
894 * Unlike exported interface, "oom" parameter is added. if oom==true, 963 * Unlike exported interface, "oom" parameter is added. if oom==true,
@@ -1087,6 +1156,10 @@ static int mem_cgroup_move_account(struct page_cgroup *pc,
1087 struct mem_cgroup_per_zone *from_mz, *to_mz; 1156 struct mem_cgroup_per_zone *from_mz, *to_mz;
1088 int nid, zid; 1157 int nid, zid;
1089 int ret = -EBUSY; 1158 int ret = -EBUSY;
1159 struct page *page;
1160 int cpu;
1161 struct mem_cgroup_stat *stat;
1162 struct mem_cgroup_stat_cpu *cpustat;
1090 1163
1091 VM_BUG_ON(from == to); 1164 VM_BUG_ON(from == to);
1092 VM_BUG_ON(PageLRU(pc->page)); 1165 VM_BUG_ON(PageLRU(pc->page));
@@ -1107,6 +1180,23 @@ static int mem_cgroup_move_account(struct page_cgroup *pc,
1107 1180
1108 res_counter_uncharge(&from->res, PAGE_SIZE); 1181 res_counter_uncharge(&from->res, PAGE_SIZE);
1109 mem_cgroup_charge_statistics(from, pc, false); 1182 mem_cgroup_charge_statistics(from, pc, false);
1183
1184 page = pc->page;
1185 if (page_is_file_cache(page) && page_mapped(page)) {
1186 cpu = smp_processor_id();
1187 /* Update mapped_file data for mem_cgroup "from" */
1188 stat = &from->stat;
1189 cpustat = &stat->cpustat[cpu];
1190 __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE,
1191 -1);
1192
1193 /* Update mapped_file data for mem_cgroup "to" */
1194 stat = &to->stat;
1195 cpustat = &stat->cpustat[cpu];
1196 __mem_cgroup_stat_add_safe(cpustat, MEM_CGROUP_STAT_MAPPED_FILE,
1197 1);
1198 }
1199
1110 if (do_swap_account) 1200 if (do_swap_account)
1111 res_counter_uncharge(&from->memsw, PAGE_SIZE); 1201 res_counter_uncharge(&from->memsw, PAGE_SIZE);
1112 css_put(&from->css); 1202 css_put(&from->css);
@@ -1422,6 +1512,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
1422 1512
1423 switch (ctype) { 1513 switch (ctype) {
1424 case MEM_CGROUP_CHARGE_TYPE_MAPPED: 1514 case MEM_CGROUP_CHARGE_TYPE_MAPPED:
1515 case MEM_CGROUP_CHARGE_TYPE_DROP:
1425 if (page_mapped(page)) 1516 if (page_mapped(page))
1426 goto unlock_out; 1517 goto unlock_out;
1427 break; 1518 break;
@@ -1485,18 +1576,23 @@ void mem_cgroup_uncharge_cache_page(struct page *page)
1485 * called after __delete_from_swap_cache() and drop "page" account. 1576 * called after __delete_from_swap_cache() and drop "page" account.
1486 * memcg information is recorded to swap_cgroup of "ent" 1577 * memcg information is recorded to swap_cgroup of "ent"
1487 */ 1578 */
1488void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent) 1579void
1580mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout)
1489{ 1581{
1490 struct mem_cgroup *memcg; 1582 struct mem_cgroup *memcg;
1583 int ctype = MEM_CGROUP_CHARGE_TYPE_SWAPOUT;
1584
1585 if (!swapout) /* this was a swap cache but the swap is unused ! */
1586 ctype = MEM_CGROUP_CHARGE_TYPE_DROP;
1587
1588 memcg = __mem_cgroup_uncharge_common(page, ctype);
1491 1589
1492 memcg = __mem_cgroup_uncharge_common(page,
1493 MEM_CGROUP_CHARGE_TYPE_SWAPOUT);
1494 /* record memcg information */ 1590 /* record memcg information */
1495 if (do_swap_account && memcg) { 1591 if (do_swap_account && swapout && memcg) {
1496 swap_cgroup_record(ent, css_id(&memcg->css)); 1592 swap_cgroup_record(ent, css_id(&memcg->css));
1497 mem_cgroup_get(memcg); 1593 mem_cgroup_get(memcg);
1498 } 1594 }
1499 if (memcg) 1595 if (swapout && memcg)
1500 css_put(&memcg->css); 1596 css_put(&memcg->css);
1501} 1597}
1502#endif 1598#endif
@@ -1674,6 +1770,12 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
1674 break; 1770 break;
1675 } 1771 }
1676 ret = res_counter_set_limit(&memcg->res, val); 1772 ret = res_counter_set_limit(&memcg->res, val);
1773 if (!ret) {
1774 if (memswlimit == val)
1775 memcg->memsw_is_minimum = true;
1776 else
1777 memcg->memsw_is_minimum = false;
1778 }
1677 mutex_unlock(&set_limit_mutex); 1779 mutex_unlock(&set_limit_mutex);
1678 1780
1679 if (!ret) 1781 if (!ret)
@@ -1692,16 +1794,14 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
1692 return ret; 1794 return ret;
1693} 1795}
1694 1796
1695int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg, 1797static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
1696 unsigned long long val) 1798 unsigned long long val)
1697{ 1799{
1698 int retry_count; 1800 int retry_count;
1699 u64 memlimit, oldusage, curusage; 1801 u64 memlimit, oldusage, curusage;
1700 int children = mem_cgroup_count_children(memcg); 1802 int children = mem_cgroup_count_children(memcg);
1701 int ret = -EBUSY; 1803 int ret = -EBUSY;
1702 1804
1703 if (!do_swap_account)
1704 return -EINVAL;
1705 /* see mem_cgroup_resize_res_limit */ 1805 /* see mem_cgroup_resize_res_limit */
1706 retry_count = children * MEM_CGROUP_RECLAIM_RETRIES; 1806 retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
1707 oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE); 1807 oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
@@ -1723,6 +1823,12 @@ int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
1723 break; 1823 break;
1724 } 1824 }
1725 ret = res_counter_set_limit(&memcg->memsw, val); 1825 ret = res_counter_set_limit(&memcg->memsw, val);
1826 if (!ret) {
1827 if (memlimit == val)
1828 memcg->memsw_is_minimum = true;
1829 else
1830 memcg->memsw_is_minimum = false;
1831 }
1726 mutex_unlock(&set_limit_mutex); 1832 mutex_unlock(&set_limit_mutex);
1727 1833
1728 if (!ret) 1834 if (!ret)
@@ -1936,8 +2042,7 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
1936 val = res_counter_read_u64(&mem->res, name); 2042 val = res_counter_read_u64(&mem->res, name);
1937 break; 2043 break;
1938 case _MEMSWAP: 2044 case _MEMSWAP:
1939 if (do_swap_account) 2045 val = res_counter_read_u64(&mem->memsw, name);
1940 val = res_counter_read_u64(&mem->memsw, name);
1941 break; 2046 break;
1942 default: 2047 default:
1943 BUG(); 2048 BUG();
@@ -2035,6 +2140,7 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
2035enum { 2140enum {
2036 MCS_CACHE, 2141 MCS_CACHE,
2037 MCS_RSS, 2142 MCS_RSS,
2143 MCS_MAPPED_FILE,
2038 MCS_PGPGIN, 2144 MCS_PGPGIN,
2039 MCS_PGPGOUT, 2145 MCS_PGPGOUT,
2040 MCS_INACTIVE_ANON, 2146 MCS_INACTIVE_ANON,
@@ -2055,6 +2161,7 @@ struct {
2055} memcg_stat_strings[NR_MCS_STAT] = { 2161} memcg_stat_strings[NR_MCS_STAT] = {
2056 {"cache", "total_cache"}, 2162 {"cache", "total_cache"},
2057 {"rss", "total_rss"}, 2163 {"rss", "total_rss"},
2164 {"mapped_file", "total_mapped_file"},
2058 {"pgpgin", "total_pgpgin"}, 2165 {"pgpgin", "total_pgpgin"},
2059 {"pgpgout", "total_pgpgout"}, 2166 {"pgpgout", "total_pgpgout"},
2060 {"inactive_anon", "total_inactive_anon"}, 2167 {"inactive_anon", "total_inactive_anon"},
@@ -2075,6 +2182,8 @@ static int mem_cgroup_get_local_stat(struct mem_cgroup *mem, void *data)
2075 s->stat[MCS_CACHE] += val * PAGE_SIZE; 2182 s->stat[MCS_CACHE] += val * PAGE_SIZE;
2076 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS); 2183 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_RSS);
2077 s->stat[MCS_RSS] += val * PAGE_SIZE; 2184 s->stat[MCS_RSS] += val * PAGE_SIZE;
2185 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_MAPPED_FILE);
2186 s->stat[MCS_MAPPED_FILE] += val * PAGE_SIZE;
2078 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT); 2187 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGIN_COUNT);
2079 s->stat[MCS_PGPGIN] += val; 2188 s->stat[MCS_PGPGIN] += val;
2080 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT); 2189 val = mem_cgroup_read_stat(&mem->stat, MEM_CGROUP_STAT_PGPGOUT_COUNT);