diff options
author | Hugh Dickins <hughd@google.com> | 2012-05-29 18:07:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-29 19:22:28 -0400 |
commit | fa9add641b1b1c564db916accac1db346e7a2759 (patch) | |
tree | 875e74ec4d7fed0018fdbc134ad899949c5e3384 /mm/memcontrol.c | |
parent | 75b00af77ed5b5a3d55549f9e0c33f3969b9330c (diff) |
mm/memcg: apply add/del_page to lruvec
Take lruvec further: pass it instead of zone to add_page_to_lru_list() and
del_page_from_lru_list(); and pagevec_lru_move_fn() pass lruvec down to
its target functions.
This cleanup eliminates a swathe of cruft in memcontrol.c, including
mem_cgroup_lru_add_list(), mem_cgroup_lru_del_list() and
mem_cgroup_lru_move_lists() - which never actually touched the lists.
In their place, mem_cgroup_page_lruvec() to decide the lruvec, previously
a side-effect of add, and mem_cgroup_update_lru_size() to maintain the
lru_size stats.
Whilst these are simplifications in their own right, the goal is to bring
the evaluation of lruvec next to the spin_locking of the lrus, in
preparation for a future patch.
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Acked-by: Michal Hocko <mhocko@suse.cz>
Acked-by: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 101 |
1 files changed, 24 insertions, 77 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 75198dac3fe8..bb8d7d3cf302 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1035,7 +1035,7 @@ EXPORT_SYMBOL(mem_cgroup_count_vm_event); | |||
1035 | /** | 1035 | /** |
1036 | * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg | 1036 | * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg |
1037 | * @zone: zone of the wanted lruvec | 1037 | * @zone: zone of the wanted lruvec |
1038 | * @mem: memcg of the wanted lruvec | 1038 | * @memcg: memcg of the wanted lruvec |
1039 | * | 1039 | * |
1040 | * Returns the lru list vector holding pages for the given @zone and | 1040 | * Returns the lru list vector holding pages for the given @zone and |
1041 | * @mem. This can be the global zone lruvec, if the memory controller | 1041 | * @mem. This can be the global zone lruvec, if the memory controller |
@@ -1068,19 +1068,11 @@ struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone, | |||
1068 | */ | 1068 | */ |
1069 | 1069 | ||
1070 | /** | 1070 | /** |
1071 | * mem_cgroup_lru_add_list - account for adding an lru page and return lruvec | 1071 | * mem_cgroup_page_lruvec - return lruvec for adding an lru page |
1072 | * @zone: zone of the page | ||
1073 | * @page: the page | 1072 | * @page: the page |
1074 | * @lru: current lru | 1073 | * @zone: zone of the page |
1075 | * | ||
1076 | * This function accounts for @page being added to @lru, and returns | ||
1077 | * the lruvec for the given @zone and the memcg @page is charged to. | ||
1078 | * | ||
1079 | * The callsite is then responsible for physically linking the page to | ||
1080 | * the returned lruvec->lists[@lru]. | ||
1081 | */ | 1074 | */ |
1082 | struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page, | 1075 | struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone) |
1083 | enum lru_list lru) | ||
1084 | { | 1076 | { |
1085 | struct mem_cgroup_per_zone *mz; | 1077 | struct mem_cgroup_per_zone *mz; |
1086 | struct mem_cgroup *memcg; | 1078 | struct mem_cgroup *memcg; |
@@ -1093,7 +1085,7 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page, | |||
1093 | memcg = pc->mem_cgroup; | 1085 | memcg = pc->mem_cgroup; |
1094 | 1086 | ||
1095 | /* | 1087 | /* |
1096 | * Surreptitiously switch any uncharged page to root: | 1088 | * Surreptitiously switch any uncharged offlist page to root: |
1097 | * an uncharged page off lru does nothing to secure | 1089 | * an uncharged page off lru does nothing to secure |
1098 | * its former mem_cgroup from sudden removal. | 1090 | * its former mem_cgroup from sudden removal. |
1099 | * | 1091 | * |
@@ -1101,65 +1093,35 @@ struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page, | |||
1101 | * under page_cgroup lock: between them, they make all uses | 1093 | * under page_cgroup lock: between them, they make all uses |
1102 | * of pc->mem_cgroup safe. | 1094 | * of pc->mem_cgroup safe. |
1103 | */ | 1095 | */ |
1104 | if (!PageCgroupUsed(pc) && memcg != root_mem_cgroup) | 1096 | if (!PageLRU(page) && !PageCgroupUsed(pc) && memcg != root_mem_cgroup) |
1105 | pc->mem_cgroup = memcg = root_mem_cgroup; | 1097 | pc->mem_cgroup = memcg = root_mem_cgroup; |
1106 | 1098 | ||
1107 | mz = page_cgroup_zoneinfo(memcg, page); | 1099 | mz = page_cgroup_zoneinfo(memcg, page); |
1108 | /* compound_order() is stabilized through lru_lock */ | ||
1109 | mz->lru_size[lru] += 1 << compound_order(page); | ||
1110 | return &mz->lruvec; | 1100 | return &mz->lruvec; |
1111 | } | 1101 | } |
1112 | 1102 | ||
1113 | /** | 1103 | /** |
1114 | * mem_cgroup_lru_del_list - account for removing an lru page | 1104 | * mem_cgroup_update_lru_size - account for adding or removing an lru page |
1115 | * @page: the page | 1105 | * @lruvec: mem_cgroup per zone lru vector |
1116 | * @lru: target lru | 1106 | * @lru: index of lru list the page is sitting on |
1107 | * @nr_pages: positive when adding or negative when removing | ||
1117 | * | 1108 | * |
1118 | * This function accounts for @page being removed from @lru. | 1109 | * This function must be called when a page is added to or removed from an |
1119 | * | 1110 | * lru list. |
1120 | * The callsite is then responsible for physically unlinking | ||
1121 | * @page->lru. | ||
1122 | */ | 1111 | */ |
1123 | void mem_cgroup_lru_del_list(struct page *page, enum lru_list lru) | 1112 | void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, |
1113 | int nr_pages) | ||
1124 | { | 1114 | { |
1125 | struct mem_cgroup_per_zone *mz; | 1115 | struct mem_cgroup_per_zone *mz; |
1126 | struct mem_cgroup *memcg; | 1116 | unsigned long *lru_size; |
1127 | struct page_cgroup *pc; | ||
1128 | 1117 | ||
1129 | if (mem_cgroup_disabled()) | 1118 | if (mem_cgroup_disabled()) |
1130 | return; | 1119 | return; |
1131 | 1120 | ||
1132 | pc = lookup_page_cgroup(page); | 1121 | mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec); |
1133 | memcg = pc->mem_cgroup; | 1122 | lru_size = mz->lru_size + lru; |
1134 | VM_BUG_ON(!memcg); | 1123 | *lru_size += nr_pages; |
1135 | mz = page_cgroup_zoneinfo(memcg, page); | 1124 | VM_BUG_ON((long)(*lru_size) < 0); |
1136 | /* huge page split is done under lru_lock. so, we have no races. */ | ||
1137 | VM_BUG_ON(mz->lru_size[lru] < (1 << compound_order(page))); | ||
1138 | mz->lru_size[lru] -= 1 << compound_order(page); | ||
1139 | } | ||
1140 | |||
1141 | /** | ||
1142 | * mem_cgroup_lru_move_lists - account for moving a page between lrus | ||
1143 | * @zone: zone of the page | ||
1144 | * @page: the page | ||
1145 | * @from: current lru | ||
1146 | * @to: target lru | ||
1147 | * | ||
1148 | * This function accounts for @page being moved between the lrus @from | ||
1149 | * and @to, and returns the lruvec for the given @zone and the memcg | ||
1150 | * @page is charged to. | ||
1151 | * | ||
1152 | * The callsite is then responsible for physically relinking | ||
1153 | * @page->lru to the returned lruvec->lists[@to]. | ||
1154 | */ | ||
1155 | struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone, | ||
1156 | struct page *page, | ||
1157 | enum lru_list from, | ||
1158 | enum lru_list to) | ||
1159 | { | ||
1160 | /* XXX: Optimize this, especially for @from == @to */ | ||
1161 | mem_cgroup_lru_del_list(page, from); | ||
1162 | return mem_cgroup_lru_add_list(zone, page, to); | ||
1163 | } | 1125 | } |
1164 | 1126 | ||
1165 | /* | 1127 | /* |
@@ -1252,24 +1214,6 @@ int mem_cgroup_inactive_file_is_low(struct lruvec *lruvec) | |||
1252 | return (active > inactive); | 1214 | return (active > inactive); |
1253 | } | 1215 | } |
1254 | 1216 | ||
1255 | struct zone_reclaim_stat * | ||
1256 | mem_cgroup_get_reclaim_stat_from_page(struct page *page) | ||
1257 | { | ||
1258 | struct page_cgroup *pc; | ||
1259 | struct mem_cgroup_per_zone *mz; | ||
1260 | |||
1261 | if (mem_cgroup_disabled()) | ||
1262 | return NULL; | ||
1263 | |||
1264 | pc = lookup_page_cgroup(page); | ||
1265 | if (!PageCgroupUsed(pc)) | ||
1266 | return NULL; | ||
1267 | /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */ | ||
1268 | smp_rmb(); | ||
1269 | mz = page_cgroup_zoneinfo(pc->mem_cgroup, page); | ||
1270 | return &mz->lruvec.reclaim_stat; | ||
1271 | } | ||
1272 | |||
1273 | #define mem_cgroup_from_res_counter(counter, member) \ | 1217 | #define mem_cgroup_from_res_counter(counter, member) \ |
1274 | container_of(counter, struct mem_cgroup, member) | 1218 | container_of(counter, struct mem_cgroup, member) |
1275 | 1219 | ||
@@ -2509,6 +2453,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, | |||
2509 | { | 2453 | { |
2510 | struct page_cgroup *pc = lookup_page_cgroup(page); | 2454 | struct page_cgroup *pc = lookup_page_cgroup(page); |
2511 | struct zone *uninitialized_var(zone); | 2455 | struct zone *uninitialized_var(zone); |
2456 | struct lruvec *lruvec; | ||
2512 | bool was_on_lru = false; | 2457 | bool was_on_lru = false; |
2513 | bool anon; | 2458 | bool anon; |
2514 | 2459 | ||
@@ -2531,8 +2476,9 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, | |||
2531 | zone = page_zone(page); | 2476 | zone = page_zone(page); |
2532 | spin_lock_irq(&zone->lru_lock); | 2477 | spin_lock_irq(&zone->lru_lock); |
2533 | if (PageLRU(page)) { | 2478 | if (PageLRU(page)) { |
2479 | lruvec = mem_cgroup_zone_lruvec(zone, pc->mem_cgroup); | ||
2534 | ClearPageLRU(page); | 2480 | ClearPageLRU(page); |
2535 | del_page_from_lru_list(zone, page, page_lru(page)); | 2481 | del_page_from_lru_list(page, lruvec, page_lru(page)); |
2536 | was_on_lru = true; | 2482 | was_on_lru = true; |
2537 | } | 2483 | } |
2538 | } | 2484 | } |
@@ -2550,9 +2496,10 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, | |||
2550 | 2496 | ||
2551 | if (lrucare) { | 2497 | if (lrucare) { |
2552 | if (was_on_lru) { | 2498 | if (was_on_lru) { |
2499 | lruvec = mem_cgroup_zone_lruvec(zone, pc->mem_cgroup); | ||
2553 | VM_BUG_ON(PageLRU(page)); | 2500 | VM_BUG_ON(PageLRU(page)); |
2554 | SetPageLRU(page); | 2501 | SetPageLRU(page); |
2555 | add_page_to_lru_list(zone, page, page_lru(page)); | 2502 | add_page_to_lru_list(page, lruvec, page_lru(page)); |
2556 | } | 2503 | } |
2557 | spin_unlock_irq(&zone->lru_lock); | 2504 | spin_unlock_irq(&zone->lru_lock); |
2558 | } | 2505 | } |