diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 125 |
1 files changed, 54 insertions, 71 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index a500cb0594c4..a9559b91603c 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -676,9 +676,11 @@ static void disarm_static_keys(struct mem_cgroup *memcg) | |||
676 | static void drain_all_stock_async(struct mem_cgroup *memcg); | 676 | static void drain_all_stock_async(struct mem_cgroup *memcg); |
677 | 677 | ||
678 | static struct mem_cgroup_per_zone * | 678 | static struct mem_cgroup_per_zone * |
679 | mem_cgroup_zoneinfo(struct mem_cgroup *memcg, int nid, int zid) | 679 | mem_cgroup_zone_zoneinfo(struct mem_cgroup *memcg, struct zone *zone) |
680 | { | 680 | { |
681 | VM_BUG_ON((unsigned)nid >= nr_node_ids); | 681 | int nid = zone_to_nid(zone); |
682 | int zid = zone_idx(zone); | ||
683 | |||
682 | return &memcg->nodeinfo[nid]->zoneinfo[zid]; | 684 | return &memcg->nodeinfo[nid]->zoneinfo[zid]; |
683 | } | 685 | } |
684 | 686 | ||
@@ -688,12 +690,12 @@ struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg) | |||
688 | } | 690 | } |
689 | 691 | ||
690 | static struct mem_cgroup_per_zone * | 692 | static struct mem_cgroup_per_zone * |
691 | page_cgroup_zoneinfo(struct mem_cgroup *memcg, struct page *page) | 693 | mem_cgroup_page_zoneinfo(struct mem_cgroup *memcg, struct page *page) |
692 | { | 694 | { |
693 | int nid = page_to_nid(page); | 695 | int nid = page_to_nid(page); |
694 | int zid = page_zonenum(page); | 696 | int zid = page_zonenum(page); |
695 | 697 | ||
696 | return mem_cgroup_zoneinfo(memcg, nid, zid); | 698 | return &memcg->nodeinfo[nid]->zoneinfo[zid]; |
697 | } | 699 | } |
698 | 700 | ||
699 | static struct mem_cgroup_tree_per_zone * | 701 | static struct mem_cgroup_tree_per_zone * |
@@ -711,11 +713,9 @@ soft_limit_tree_from_page(struct page *page) | |||
711 | return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid]; | 713 | return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid]; |
712 | } | 714 | } |
713 | 715 | ||
714 | static void | 716 | static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz, |
715 | __mem_cgroup_insert_exceeded(struct mem_cgroup *memcg, | 717 | struct mem_cgroup_tree_per_zone *mctz, |
716 | struct mem_cgroup_per_zone *mz, | 718 | unsigned long long new_usage_in_excess) |
717 | struct mem_cgroup_tree_per_zone *mctz, | ||
718 | unsigned long long new_usage_in_excess) | ||
719 | { | 719 | { |
720 | struct rb_node **p = &mctz->rb_root.rb_node; | 720 | struct rb_node **p = &mctz->rb_root.rb_node; |
721 | struct rb_node *parent = NULL; | 721 | struct rb_node *parent = NULL; |
@@ -745,10 +745,8 @@ __mem_cgroup_insert_exceeded(struct mem_cgroup *memcg, | |||
745 | mz->on_tree = true; | 745 | mz->on_tree = true; |
746 | } | 746 | } |
747 | 747 | ||
748 | static void | 748 | static void __mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz, |
749 | __mem_cgroup_remove_exceeded(struct mem_cgroup *memcg, | 749 | struct mem_cgroup_tree_per_zone *mctz) |
750 | struct mem_cgroup_per_zone *mz, | ||
751 | struct mem_cgroup_tree_per_zone *mctz) | ||
752 | { | 750 | { |
753 | if (!mz->on_tree) | 751 | if (!mz->on_tree) |
754 | return; | 752 | return; |
@@ -756,13 +754,11 @@ __mem_cgroup_remove_exceeded(struct mem_cgroup *memcg, | |||
756 | mz->on_tree = false; | 754 | mz->on_tree = false; |
757 | } | 755 | } |
758 | 756 | ||
759 | static void | 757 | static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz, |
760 | mem_cgroup_remove_exceeded(struct mem_cgroup *memcg, | 758 | struct mem_cgroup_tree_per_zone *mctz) |
761 | struct mem_cgroup_per_zone *mz, | ||
762 | struct mem_cgroup_tree_per_zone *mctz) | ||
763 | { | 759 | { |
764 | spin_lock(&mctz->lock); | 760 | spin_lock(&mctz->lock); |
765 | __mem_cgroup_remove_exceeded(memcg, mz, mctz); | 761 | __mem_cgroup_remove_exceeded(mz, mctz); |
766 | spin_unlock(&mctz->lock); | 762 | spin_unlock(&mctz->lock); |
767 | } | 763 | } |
768 | 764 | ||
@@ -772,16 +768,14 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) | |||
772 | unsigned long long excess; | 768 | unsigned long long excess; |
773 | struct mem_cgroup_per_zone *mz; | 769 | struct mem_cgroup_per_zone *mz; |
774 | struct mem_cgroup_tree_per_zone *mctz; | 770 | struct mem_cgroup_tree_per_zone *mctz; |
775 | int nid = page_to_nid(page); | ||
776 | int zid = page_zonenum(page); | ||
777 | mctz = soft_limit_tree_from_page(page); | ||
778 | 771 | ||
772 | mctz = soft_limit_tree_from_page(page); | ||
779 | /* | 773 | /* |
780 | * Necessary to update all ancestors when hierarchy is used. | 774 | * Necessary to update all ancestors when hierarchy is used. |
781 | * because their event counter is not touched. | 775 | * because their event counter is not touched. |
782 | */ | 776 | */ |
783 | for (; memcg; memcg = parent_mem_cgroup(memcg)) { | 777 | for (; memcg; memcg = parent_mem_cgroup(memcg)) { |
784 | mz = mem_cgroup_zoneinfo(memcg, nid, zid); | 778 | mz = mem_cgroup_page_zoneinfo(memcg, page); |
785 | excess = res_counter_soft_limit_excess(&memcg->res); | 779 | excess = res_counter_soft_limit_excess(&memcg->res); |
786 | /* | 780 | /* |
787 | * We have to update the tree if mz is on RB-tree or | 781 | * We have to update the tree if mz is on RB-tree or |
@@ -791,12 +785,12 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) | |||
791 | spin_lock(&mctz->lock); | 785 | spin_lock(&mctz->lock); |
792 | /* if on-tree, remove it */ | 786 | /* if on-tree, remove it */ |
793 | if (mz->on_tree) | 787 | if (mz->on_tree) |
794 | __mem_cgroup_remove_exceeded(memcg, mz, mctz); | 788 | __mem_cgroup_remove_exceeded(mz, mctz); |
795 | /* | 789 | /* |
796 | * Insert again. mz->usage_in_excess will be updated. | 790 | * Insert again. mz->usage_in_excess will be updated. |
797 | * If excess is 0, no tree ops. | 791 | * If excess is 0, no tree ops. |
798 | */ | 792 | */ |
799 | __mem_cgroup_insert_exceeded(memcg, mz, mctz, excess); | 793 | __mem_cgroup_insert_exceeded(mz, mctz, excess); |
800 | spin_unlock(&mctz->lock); | 794 | spin_unlock(&mctz->lock); |
801 | } | 795 | } |
802 | } | 796 | } |
@@ -804,15 +798,15 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) | |||
804 | 798 | ||
805 | static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg) | 799 | static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg) |
806 | { | 800 | { |
807 | int node, zone; | ||
808 | struct mem_cgroup_per_zone *mz; | ||
809 | struct mem_cgroup_tree_per_zone *mctz; | 801 | struct mem_cgroup_tree_per_zone *mctz; |
802 | struct mem_cgroup_per_zone *mz; | ||
803 | int nid, zid; | ||
810 | 804 | ||
811 | for_each_node(node) { | 805 | for_each_node(nid) { |
812 | for (zone = 0; zone < MAX_NR_ZONES; zone++) { | 806 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { |
813 | mz = mem_cgroup_zoneinfo(memcg, node, zone); | 807 | mz = &memcg->nodeinfo[nid]->zoneinfo[zid]; |
814 | mctz = soft_limit_tree_node_zone(node, zone); | 808 | mctz = soft_limit_tree_node_zone(nid, zid); |
815 | mem_cgroup_remove_exceeded(memcg, mz, mctz); | 809 | mem_cgroup_remove_exceeded(mz, mctz); |
816 | } | 810 | } |
817 | } | 811 | } |
818 | } | 812 | } |
@@ -835,7 +829,7 @@ retry: | |||
835 | * we will to add it back at the end of reclaim to its correct | 829 | * we will to add it back at the end of reclaim to its correct |
836 | * position in the tree. | 830 | * position in the tree. |
837 | */ | 831 | */ |
838 | __mem_cgroup_remove_exceeded(mz->memcg, mz, mctz); | 832 | __mem_cgroup_remove_exceeded(mz, mctz); |
839 | if (!res_counter_soft_limit_excess(&mz->memcg->res) || | 833 | if (!res_counter_soft_limit_excess(&mz->memcg->res) || |
840 | !css_tryget(&mz->memcg->css)) | 834 | !css_tryget(&mz->memcg->css)) |
841 | goto retry; | 835 | goto retry; |
@@ -946,8 +940,7 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg, | |||
946 | __this_cpu_add(memcg->stat->nr_page_events, nr_pages); | 940 | __this_cpu_add(memcg->stat->nr_page_events, nr_pages); |
947 | } | 941 | } |
948 | 942 | ||
949 | unsigned long | 943 | unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru) |
950 | mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru) | ||
951 | { | 944 | { |
952 | struct mem_cgroup_per_zone *mz; | 945 | struct mem_cgroup_per_zone *mz; |
953 | 946 | ||
@@ -955,46 +948,38 @@ mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru) | |||
955 | return mz->lru_size[lru]; | 948 | return mz->lru_size[lru]; |
956 | } | 949 | } |
957 | 950 | ||
958 | static unsigned long | 951 | static unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg, |
959 | mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg, int nid, int zid, | 952 | int nid, |
960 | unsigned int lru_mask) | 953 | unsigned int lru_mask) |
961 | { | 954 | { |
962 | struct mem_cgroup_per_zone *mz; | 955 | unsigned long nr = 0; |
963 | enum lru_list lru; | ||
964 | unsigned long ret = 0; | ||
965 | |||
966 | mz = mem_cgroup_zoneinfo(memcg, nid, zid); | ||
967 | |||
968 | for_each_lru(lru) { | ||
969 | if (BIT(lru) & lru_mask) | ||
970 | ret += mz->lru_size[lru]; | ||
971 | } | ||
972 | return ret; | ||
973 | } | ||
974 | |||
975 | static unsigned long | ||
976 | mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg, | ||
977 | int nid, unsigned int lru_mask) | ||
978 | { | ||
979 | u64 total = 0; | ||
980 | int zid; | 956 | int zid; |
981 | 957 | ||
982 | for (zid = 0; zid < MAX_NR_ZONES; zid++) | 958 | VM_BUG_ON((unsigned)nid >= nr_node_ids); |
983 | total += mem_cgroup_zone_nr_lru_pages(memcg, | ||
984 | nid, zid, lru_mask); | ||
985 | 959 | ||
986 | return total; | 960 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { |
961 | struct mem_cgroup_per_zone *mz; | ||
962 | enum lru_list lru; | ||
963 | |||
964 | for_each_lru(lru) { | ||
965 | if (!(BIT(lru) & lru_mask)) | ||
966 | continue; | ||
967 | mz = &memcg->nodeinfo[nid]->zoneinfo[zid]; | ||
968 | nr += mz->lru_size[lru]; | ||
969 | } | ||
970 | } | ||
971 | return nr; | ||
987 | } | 972 | } |
988 | 973 | ||
989 | static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg, | 974 | static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg, |
990 | unsigned int lru_mask) | 975 | unsigned int lru_mask) |
991 | { | 976 | { |
977 | unsigned long nr = 0; | ||
992 | int nid; | 978 | int nid; |
993 | u64 total = 0; | ||
994 | 979 | ||
995 | for_each_node_state(nid, N_MEMORY) | 980 | for_each_node_state(nid, N_MEMORY) |
996 | total += mem_cgroup_node_nr_lru_pages(memcg, nid, lru_mask); | 981 | nr += mem_cgroup_node_nr_lru_pages(memcg, nid, lru_mask); |
997 | return total; | 982 | return nr; |
998 | } | 983 | } |
999 | 984 | ||
1000 | static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg, | 985 | static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg, |
@@ -1242,11 +1227,9 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root, | |||
1242 | int uninitialized_var(seq); | 1227 | int uninitialized_var(seq); |
1243 | 1228 | ||
1244 | if (reclaim) { | 1229 | if (reclaim) { |
1245 | int nid = zone_to_nid(reclaim->zone); | ||
1246 | int zid = zone_idx(reclaim->zone); | ||
1247 | struct mem_cgroup_per_zone *mz; | 1230 | struct mem_cgroup_per_zone *mz; |
1248 | 1231 | ||
1249 | mz = mem_cgroup_zoneinfo(root, nid, zid); | 1232 | mz = mem_cgroup_zone_zoneinfo(root, reclaim->zone); |
1250 | iter = &mz->reclaim_iter[reclaim->priority]; | 1233 | iter = &mz->reclaim_iter[reclaim->priority]; |
1251 | if (prev && reclaim->generation != iter->generation) { | 1234 | if (prev && reclaim->generation != iter->generation) { |
1252 | iter->last_visited = NULL; | 1235 | iter->last_visited = NULL; |
@@ -1353,7 +1336,7 @@ struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone, | |||
1353 | goto out; | 1336 | goto out; |
1354 | } | 1337 | } |
1355 | 1338 | ||
1356 | mz = mem_cgroup_zoneinfo(memcg, zone_to_nid(zone), zone_idx(zone)); | 1339 | mz = mem_cgroup_zone_zoneinfo(memcg, zone); |
1357 | lruvec = &mz->lruvec; | 1340 | lruvec = &mz->lruvec; |
1358 | out: | 1341 | out: |
1359 | /* | 1342 | /* |
@@ -1412,7 +1395,7 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone) | |||
1412 | if (!PageLRU(page) && !PageCgroupUsed(pc) && memcg != root_mem_cgroup) | 1395 | if (!PageLRU(page) && !PageCgroupUsed(pc) && memcg != root_mem_cgroup) |
1413 | pc->mem_cgroup = memcg = root_mem_cgroup; | 1396 | pc->mem_cgroup = memcg = root_mem_cgroup; |
1414 | 1397 | ||
1415 | mz = page_cgroup_zoneinfo(memcg, page); | 1398 | mz = mem_cgroup_page_zoneinfo(memcg, page); |
1416 | lruvec = &mz->lruvec; | 1399 | lruvec = &mz->lruvec; |
1417 | out: | 1400 | out: |
1418 | /* | 1401 | /* |
@@ -1550,7 +1533,7 @@ static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg) | |||
1550 | int mem_cgroup_swappiness(struct mem_cgroup *memcg) | 1533 | int mem_cgroup_swappiness(struct mem_cgroup *memcg) |
1551 | { | 1534 | { |
1552 | /* root ? */ | 1535 | /* root ? */ |
1553 | if (!css_parent(&memcg->css)) | 1536 | if (mem_cgroup_disabled() || !css_parent(&memcg->css)) |
1554 | return vm_swappiness; | 1537 | return vm_swappiness; |
1555 | 1538 | ||
1556 | return memcg->swappiness; | 1539 | return memcg->swappiness; |
@@ -4597,7 +4580,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, | |||
4597 | break; | 4580 | break; |
4598 | } while (1); | 4581 | } while (1); |
4599 | } | 4582 | } |
4600 | __mem_cgroup_remove_exceeded(mz->memcg, mz, mctz); | 4583 | __mem_cgroup_remove_exceeded(mz, mctz); |
4601 | excess = res_counter_soft_limit_excess(&mz->memcg->res); | 4584 | excess = res_counter_soft_limit_excess(&mz->memcg->res); |
4602 | /* | 4585 | /* |
4603 | * One school of thought says that we should not add | 4586 | * One school of thought says that we should not add |
@@ -4608,7 +4591,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, | |||
4608 | * term TODO. | 4591 | * term TODO. |
4609 | */ | 4592 | */ |
4610 | /* If excess == 0, no tree ops */ | 4593 | /* If excess == 0, no tree ops */ |
4611 | __mem_cgroup_insert_exceeded(mz->memcg, mz, mctz, excess); | 4594 | __mem_cgroup_insert_exceeded(mz, mctz, excess); |
4612 | spin_unlock(&mctz->lock); | 4595 | spin_unlock(&mctz->lock); |
4613 | css_put(&mz->memcg->css); | 4596 | css_put(&mz->memcg->css); |
4614 | loop++; | 4597 | loop++; |
@@ -5305,7 +5288,7 @@ static int memcg_stat_show(struct seq_file *m, void *v) | |||
5305 | 5288 | ||
5306 | for_each_online_node(nid) | 5289 | for_each_online_node(nid) |
5307 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { | 5290 | for (zid = 0; zid < MAX_NR_ZONES; zid++) { |
5308 | mz = mem_cgroup_zoneinfo(memcg, nid, zid); | 5291 | mz = &memcg->nodeinfo[nid]->zoneinfo[zid]; |
5309 | rstat = &mz->lruvec.reclaim_stat; | 5292 | rstat = &mz->lruvec.reclaim_stat; |
5310 | 5293 | ||
5311 | recent_rotated[0] += rstat->recent_rotated[0]; | 5294 | recent_rotated[0] += rstat->recent_rotated[0]; |