aboutsummaryrefslogtreecommitdiffstats
path: root/mm/rmap.c
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2016-01-15 19:52:16 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-15 20:56:32 -0500
commitd281ee6145183594788ab6d5b55f8d144e69eace (patch)
tree08b535efb69098d6cb9eef938ad63316be2d70b4 /mm/rmap.c
parentafd9883f93b6d030682d7072852b50c5a1b17b63 (diff)
rmap: add argument to charge compound page
We're going to allow mapping of individual 4k pages of THP compound page. It means we cannot rely on PageTransHuge() check to decide if map/unmap small page or THP. The patch adds new argument to rmap functions to indicate whether we want to operate on whole compound page or only the small page. [n-horiguchi@ah.jp.nec.com: fix mapcount mismatch in hugepage migration] Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Tested-by: Sasha Levin <sasha.levin@oracle.com> Tested-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Acked-by: Jerome Marchand <jmarchan@redhat.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Rik van Riel <riel@redhat.com> Cc: Steve Capper <steve.capper@linaro.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.cz> Cc: Christoph Lameter <cl@linux.com> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/rmap.c')
-rw-r--r--mm/rmap.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index 622756c16ac8..c330f9aba63a 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1133,6 +1133,7 @@ static void __page_check_anon_rmap(struct page *page,
1133 * @page: the page to add the mapping to 1133 * @page: the page to add the mapping to
1134 * @vma: the vm area in which the mapping is added 1134 * @vma: the vm area in which the mapping is added
1135 * @address: the user virtual address mapped 1135 * @address: the user virtual address mapped
1136 * @compound: charge the page as compound or small page
1136 * 1137 *
1137 * The caller needs to hold the pte lock, and the page must be locked in 1138 * The caller needs to hold the pte lock, and the page must be locked in
1138 * the anon_vma case: to serialize mapping,index checking after setting, 1139 * the anon_vma case: to serialize mapping,index checking after setting,
@@ -1140,9 +1141,9 @@ static void __page_check_anon_rmap(struct page *page,
1140 * (but PageKsm is never downgraded to PageAnon). 1141 * (but PageKsm is never downgraded to PageAnon).
1141 */ 1142 */
1142void page_add_anon_rmap(struct page *page, 1143void page_add_anon_rmap(struct page *page,
1143 struct vm_area_struct *vma, unsigned long address) 1144 struct vm_area_struct *vma, unsigned long address, bool compound)
1144{ 1145{
1145 do_page_add_anon_rmap(page, vma, address, 0); 1146 do_page_add_anon_rmap(page, vma, address, compound ? RMAP_COMPOUND : 0);
1146} 1147}
1147 1148
1148/* 1149/*
@@ -1151,21 +1152,24 @@ void page_add_anon_rmap(struct page *page,
1151 * Everybody else should continue to use page_add_anon_rmap above. 1152 * Everybody else should continue to use page_add_anon_rmap above.
1152 */ 1153 */
1153void do_page_add_anon_rmap(struct page *page, 1154void do_page_add_anon_rmap(struct page *page,
1154 struct vm_area_struct *vma, unsigned long address, int exclusive) 1155 struct vm_area_struct *vma, unsigned long address, int flags)
1155{ 1156{
1156 int first = atomic_inc_and_test(&page->_mapcount); 1157 int first = atomic_inc_and_test(&page->_mapcount);
1157 if (first) { 1158 if (first) {
1159 bool compound = flags & RMAP_COMPOUND;
1160 int nr = compound ? hpage_nr_pages(page) : 1;
1158 /* 1161 /*
1159 * We use the irq-unsafe __{inc|mod}_zone_page_stat because 1162 * We use the irq-unsafe __{inc|mod}_zone_page_stat because
1160 * these counters are not modified in interrupt context, and 1163 * these counters are not modified in interrupt context, and
1161 * pte lock(a spinlock) is held, which implies preemption 1164 * pte lock(a spinlock) is held, which implies preemption
1162 * disabled. 1165 * disabled.
1163 */ 1166 */
1164 if (PageTransHuge(page)) 1167 if (compound) {
1168 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
1165 __inc_zone_page_state(page, 1169 __inc_zone_page_state(page,
1166 NR_ANON_TRANSPARENT_HUGEPAGES); 1170 NR_ANON_TRANSPARENT_HUGEPAGES);
1167 __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, 1171 }
1168 hpage_nr_pages(page)); 1172 __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
1169 } 1173 }
1170 if (unlikely(PageKsm(page))) 1174 if (unlikely(PageKsm(page)))
1171 return; 1175 return;
@@ -1173,7 +1177,8 @@ void do_page_add_anon_rmap(struct page *page,
1173 VM_BUG_ON_PAGE(!PageLocked(page), page); 1177 VM_BUG_ON_PAGE(!PageLocked(page), page);
1174 /* address might be in next vma when migration races vma_adjust */ 1178 /* address might be in next vma when migration races vma_adjust */
1175 if (first) 1179 if (first)
1176 __page_set_anon_rmap(page, vma, address, exclusive); 1180 __page_set_anon_rmap(page, vma, address,
1181 flags & RMAP_EXCLUSIVE);
1177 else 1182 else
1178 __page_check_anon_rmap(page, vma, address); 1183 __page_check_anon_rmap(page, vma, address);
1179} 1184}
@@ -1183,21 +1188,25 @@ void do_page_add_anon_rmap(struct page *page,
1183 * @page: the page to add the mapping to 1188 * @page: the page to add the mapping to
1184 * @vma: the vm area in which the mapping is added 1189 * @vma: the vm area in which the mapping is added
1185 * @address: the user virtual address mapped 1190 * @address: the user virtual address mapped
1191 * @compound: charge the page as compound or small page
1186 * 1192 *
1187 * Same as page_add_anon_rmap but must only be called on *new* pages. 1193 * Same as page_add_anon_rmap but must only be called on *new* pages.
1188 * This means the inc-and-test can be bypassed. 1194 * This means the inc-and-test can be bypassed.
1189 * Page does not have to be locked. 1195 * Page does not have to be locked.
1190 */ 1196 */
1191void page_add_new_anon_rmap(struct page *page, 1197void page_add_new_anon_rmap(struct page *page,
1192 struct vm_area_struct *vma, unsigned long address) 1198 struct vm_area_struct *vma, unsigned long address, bool compound)
1193{ 1199{
1200 int nr = compound ? hpage_nr_pages(page) : 1;
1201
1194 VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma); 1202 VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma);
1195 SetPageSwapBacked(page); 1203 SetPageSwapBacked(page);
1196 atomic_set(&page->_mapcount, 0); /* increment count (starts at -1) */ 1204 atomic_set(&page->_mapcount, 0); /* increment count (starts at -1) */
1197 if (PageTransHuge(page)) 1205 if (compound) {
1206 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
1198 __inc_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES); 1207 __inc_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
1199 __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, 1208 }
1200 hpage_nr_pages(page)); 1209 __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, nr);
1201 __page_set_anon_rmap(page, vma, address, 1); 1210 __page_set_anon_rmap(page, vma, address, 1);
1202} 1211}
1203 1212
@@ -1249,13 +1258,17 @@ out:
1249 1258
1250/** 1259/**
1251 * page_remove_rmap - take down pte mapping from a page 1260 * page_remove_rmap - take down pte mapping from a page
1252 * @page: page to remove mapping from 1261 * @page: page to remove mapping from
1262 * @compound: uncharge the page as compound or small page
1253 * 1263 *
1254 * The caller needs to hold the pte lock. 1264 * The caller needs to hold the pte lock.
1255 */ 1265 */
1256void page_remove_rmap(struct page *page) 1266void page_remove_rmap(struct page *page, bool compound)
1257{ 1267{
1268 int nr = compound ? hpage_nr_pages(page) : 1;
1269
1258 if (!PageAnon(page)) { 1270 if (!PageAnon(page)) {
1271 VM_BUG_ON_PAGE(compound && !PageHuge(page), page);
1259 page_remove_file_rmap(page); 1272 page_remove_file_rmap(page);
1260 return; 1273 return;
1261 } 1274 }
@@ -1273,11 +1286,12 @@ void page_remove_rmap(struct page *page)
1273 * these counters are not modified in interrupt context, and 1286 * these counters are not modified in interrupt context, and
1274 * pte lock(a spinlock) is held, which implies preemption disabled. 1287 * pte lock(a spinlock) is held, which implies preemption disabled.
1275 */ 1288 */
1276 if (PageTransHuge(page)) 1289 if (compound) {
1290 VM_BUG_ON_PAGE(!PageTransHuge(page), page);
1277 __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES); 1291 __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
1292 }
1278 1293
1279 __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, 1294 __mod_zone_page_state(page_zone(page), NR_ANON_PAGES, -nr);
1280 -hpage_nr_pages(page));
1281 1295
1282 if (unlikely(PageMlocked(page))) 1296 if (unlikely(PageMlocked(page)))
1283 clear_page_mlock(page); 1297 clear_page_mlock(page);
@@ -1416,7 +1430,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
1416 } else 1430 } else
1417 dec_mm_counter(mm, mm_counter_file(page)); 1431 dec_mm_counter(mm, mm_counter_file(page));
1418 1432
1419 page_remove_rmap(page); 1433 page_remove_rmap(page, PageHuge(page));
1420 page_cache_release(page); 1434 page_cache_release(page);
1421 1435
1422out_unmap: 1436out_unmap: