aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/memcontrol.h35
-rw-r--r--mm/memcontrol.c62
-rw-r--r--mm/rmap.c28
3 files changed, 101 insertions, 24 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index c54e5dfa1962..bf7ae01fc93b 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -141,6 +141,31 @@ static inline bool mem_cgroup_disabled(void)
141 return false; 141 return false;
142} 142}
143 143
144void __mem_cgroup_begin_update_page_stat(struct page *page, bool *locked,
145 unsigned long *flags);
146
147static inline void mem_cgroup_begin_update_page_stat(struct page *page,
148 bool *locked, unsigned long *flags)
149{
150 if (mem_cgroup_disabled())
151 return;
152 rcu_read_lock();
153 *locked = false;
154 return __mem_cgroup_begin_update_page_stat(page, locked, flags);
155}
156
157void __mem_cgroup_end_update_page_stat(struct page *page,
158 unsigned long *flags);
159static inline void mem_cgroup_end_update_page_stat(struct page *page,
160 bool *locked, unsigned long *flags)
161{
162 if (mem_cgroup_disabled())
163 return;
164 if (*locked)
165 __mem_cgroup_end_update_page_stat(page, flags);
166 rcu_read_unlock();
167}
168
144void mem_cgroup_update_page_stat(struct page *page, 169void mem_cgroup_update_page_stat(struct page *page,
145 enum mem_cgroup_page_stat_item idx, 170 enum mem_cgroup_page_stat_item idx,
146 int val); 171 int val);
@@ -341,6 +366,16 @@ mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
341{ 366{
342} 367}
343 368
369static inline void mem_cgroup_begin_update_page_stat(struct page *page,
370 bool *locked, unsigned long *flags)
371{
372}
373
374static inline void mem_cgroup_end_update_page_stat(struct page *page,
375 bool *locked, unsigned long *flags)
376{
377}
378
344static inline void mem_cgroup_inc_page_stat(struct page *page, 379static inline void mem_cgroup_inc_page_stat(struct page *page,
345 enum mem_cgroup_page_stat_item idx) 380 enum mem_cgroup_page_stat_item idx)
346{ 381{
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 8afed2819b8f..df1e180f6c30 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1910,32 +1910,59 @@ bool mem_cgroup_handle_oom(struct mem_cgroup *memcg, gfp_t mask, int order)
1910 * If there is, we take a lock. 1910 * If there is, we take a lock.
1911 */ 1911 */
1912 1912
1913void __mem_cgroup_begin_update_page_stat(struct page *page,
1914 bool *locked, unsigned long *flags)
1915{
1916 struct mem_cgroup *memcg;
1917 struct page_cgroup *pc;
1918
1919 pc = lookup_page_cgroup(page);
1920again:
1921 memcg = pc->mem_cgroup;
1922 if (unlikely(!memcg || !PageCgroupUsed(pc)))
1923 return;
1924 /*
1925 * If this memory cgroup is not under account moving, we don't
1926 * need to take move_lock_page_cgroup(). Because we already hold
1927 * rcu_read_lock(), any calls to move_account will be delayed until
1928 * rcu_read_unlock() if mem_cgroup_stealed() == true.
1929 */
1930 if (!mem_cgroup_stealed(memcg))
1931 return;
1932
1933 move_lock_mem_cgroup(memcg, flags);
1934 if (memcg != pc->mem_cgroup || !PageCgroupUsed(pc)) {
1935 move_unlock_mem_cgroup(memcg, flags);
1936 goto again;
1937 }
1938 *locked = true;
1939}
1940
1941void __mem_cgroup_end_update_page_stat(struct page *page, unsigned long *flags)
1942{
1943 struct page_cgroup *pc = lookup_page_cgroup(page);
1944
1945 /*
1946 * It's guaranteed that pc->mem_cgroup never changes while
1947 * lock is held because a routine modifies pc->mem_cgroup
1948 * should take move_lock_page_cgroup().
1949 */
1950 move_unlock_mem_cgroup(pc->mem_cgroup, flags);
1951}
1952
1913void mem_cgroup_update_page_stat(struct page *page, 1953void mem_cgroup_update_page_stat(struct page *page,
1914 enum mem_cgroup_page_stat_item idx, int val) 1954 enum mem_cgroup_page_stat_item idx, int val)
1915{ 1955{
1916 struct mem_cgroup *memcg; 1956 struct mem_cgroup *memcg;
1917 struct page_cgroup *pc = lookup_page_cgroup(page); 1957 struct page_cgroup *pc = lookup_page_cgroup(page);
1918 bool need_unlock = false;
1919 unsigned long uninitialized_var(flags); 1958 unsigned long uninitialized_var(flags);
1920 1959
1921 if (mem_cgroup_disabled()) 1960 if (mem_cgroup_disabled())
1922 return; 1961 return;
1923again: 1962
1924 rcu_read_lock();
1925 memcg = pc->mem_cgroup; 1963 memcg = pc->mem_cgroup;
1926 if (unlikely(!memcg || !PageCgroupUsed(pc))) 1964 if (unlikely(!memcg || !PageCgroupUsed(pc)))
1927 goto out; 1965 return;
1928 /* pc->mem_cgroup is unstable ? */
1929 if (unlikely(mem_cgroup_stealed(memcg))) {
1930 /* take a lock against to access pc->mem_cgroup */
1931 move_lock_mem_cgroup(memcg, &flags);
1932 if (memcg != pc->mem_cgroup || !PageCgroupUsed(pc)) {
1933 move_unlock_mem_cgroup(memcg, &flags);
1934 rcu_read_unlock();
1935 goto again;
1936 }
1937 need_unlock = true;
1938 }
1939 1966
1940 switch (idx) { 1967 switch (idx) {
1941 case MEMCG_NR_FILE_MAPPED: 1968 case MEMCG_NR_FILE_MAPPED:
@@ -1950,11 +1977,6 @@ again:
1950 } 1977 }
1951 1978
1952 this_cpu_add(memcg->stat->count[idx], val); 1979 this_cpu_add(memcg->stat->count[idx], val);
1953
1954out:
1955 if (unlikely(need_unlock))
1956 move_unlock_mem_cgroup(memcg, &flags);
1957 rcu_read_unlock();
1958} 1980}
1959 1981
1960/* 1982/*
diff --git a/mm/rmap.c b/mm/rmap.c
index ebeb95e9150a..5b5ad584ffb7 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1148,10 +1148,15 @@ void page_add_new_anon_rmap(struct page *page,
1148 */ 1148 */
1149void page_add_file_rmap(struct page *page) 1149void page_add_file_rmap(struct page *page)
1150{ 1150{
1151 bool locked;
1152 unsigned long flags;
1153
1154 mem_cgroup_begin_update_page_stat(page, &locked, &flags);
1151 if (atomic_inc_and_test(&page->_mapcount)) { 1155 if (atomic_inc_and_test(&page->_mapcount)) {
1152 __inc_zone_page_state(page, NR_FILE_MAPPED); 1156 __inc_zone_page_state(page, NR_FILE_MAPPED);
1153 mem_cgroup_inc_page_stat(page, MEMCG_NR_FILE_MAPPED); 1157 mem_cgroup_inc_page_stat(page, MEMCG_NR_FILE_MAPPED);
1154 } 1158 }
1159 mem_cgroup_end_update_page_stat(page, &locked, &flags);
1155} 1160}
1156 1161
1157/** 1162/**
@@ -1162,9 +1167,21 @@ void page_add_file_rmap(struct page *page)
1162 */ 1167 */
1163void page_remove_rmap(struct page *page) 1168void page_remove_rmap(struct page *page)
1164{ 1169{
1170 bool anon = PageAnon(page);
1171 bool locked;
1172 unsigned long flags;
1173
1174 /*
1175 * The anon case has no mem_cgroup page_stat to update; but may
1176 * uncharge_page() below, where the lock ordering can deadlock if
1177 * we hold the lock against page_stat move: so avoid it on anon.
1178 */
1179 if (!anon)
1180 mem_cgroup_begin_update_page_stat(page, &locked, &flags);
1181
1165 /* page still mapped by someone else? */ 1182 /* page still mapped by someone else? */
1166 if (!atomic_add_negative(-1, &page->_mapcount)) 1183 if (!atomic_add_negative(-1, &page->_mapcount))
1167 return; 1184 goto out;
1168 1185
1169 /* 1186 /*
1170 * Now that the last pte has gone, s390 must transfer dirty 1187 * Now that the last pte has gone, s390 must transfer dirty
@@ -1173,7 +1190,7 @@ void page_remove_rmap(struct page *page)
1173 * not if it's in swapcache - there might be another pte slot 1190 * not if it's in swapcache - there might be another pte slot
1174 * containing the swap entry, but page not yet written to swap. 1191 * containing the swap entry, but page not yet written to swap.
1175 */ 1192 */
1176 if ((!PageAnon(page) || PageSwapCache(page)) && 1193 if ((!anon || PageSwapCache(page)) &&
1177 page_test_and_clear_dirty(page_to_pfn(page), 1)) 1194 page_test_and_clear_dirty(page_to_pfn(page), 1))
1178 set_page_dirty(page); 1195 set_page_dirty(page);
1179 /* 1196 /*
@@ -1181,8 +1198,8 @@ void page_remove_rmap(struct page *page)
1181 * and not charged by memcg for now. 1198 * and not charged by memcg for now.
1182 */ 1199 */
1183 if (unlikely(PageHuge(page))) 1200 if (unlikely(PageHuge(page)))
1184 return; 1201 goto out;
1185 if (PageAnon(page)) { 1202 if (anon) {
1186 mem_cgroup_uncharge_page(page); 1203 mem_cgroup_uncharge_page(page);
1187 if (!PageTransHuge(page)) 1204 if (!PageTransHuge(page))
1188 __dec_zone_page_state(page, NR_ANON_PAGES); 1205 __dec_zone_page_state(page, NR_ANON_PAGES);
@@ -1202,6 +1219,9 @@ void page_remove_rmap(struct page *page)
1202 * Leaving it set also helps swapoff to reinstate ptes 1219 * Leaving it set also helps swapoff to reinstate ptes
1203 * faster for those pages still in swapcache. 1220 * faster for those pages still in swapcache.
1204 */ 1221 */
1222out:
1223 if (!anon)
1224 mem_cgroup_end_update_page_stat(page, &locked, &flags);
1205} 1225}
1206 1226
1207/* 1227/*