aboutsummaryrefslogtreecommitdiffstats
path: root/mm/rmap.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-12 13:15:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-12 13:15:10 -0400
commit1021a645344d4a77333e19e60d37b9343be0d7b7 (patch)
tree7a78ab55f27f97209ed1b85ccfd88c6d5b8416d3 /mm/rmap.c
parent7367f5b013fee33f7d40a5a10a39d5134f529ec8 (diff)
parent28957a5467bab9ed51a237d21e31055fad987887 (diff)
Merge branch 'hwpoison' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6
* 'hwpoison' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6: hugetlb: add missing unlock in avoidcopy path in hugetlb_cow() hwpoison: rename CONFIG HWPOISON, hugetlb: support hwpoison injection for hugepage HWPOISON, hugetlb: detect hwpoison in hugetlb code HWPOISON, hugetlb: isolate corrupted hugepage HWPOISON, hugetlb: maintain mce_bad_pages in handling hugepage error HWPOISON, hugetlb: set/clear PG_hwpoison bits on hugepage HWPOISON, hugetlb: enable error handling path for hugepage hugetlb, rmap: add reverse mapping for hugepage hugetlb: move definition of is_vm_hugetlb_page() to hugepage_inline.h Fix up trivial conflicts in mm/memory-failure.c
Diffstat (limited to 'mm/rmap.c')
-rw-r--r--mm/rmap.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index a7d0f5482634..87b9e8ad4509 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -56,6 +56,7 @@
56#include <linux/memcontrol.h> 56#include <linux/memcontrol.h>
57#include <linux/mmu_notifier.h> 57#include <linux/mmu_notifier.h>
58#include <linux/migrate.h> 58#include <linux/migrate.h>
59#include <linux/hugetlb.h>
59 60
60#include <asm/tlbflush.h> 61#include <asm/tlbflush.h>
61 62
@@ -350,6 +351,8 @@ vma_address(struct page *page, struct vm_area_struct *vma)
350 pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); 351 pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
351 unsigned long address; 352 unsigned long address;
352 353
354 if (unlikely(is_vm_hugetlb_page(vma)))
355 pgoff = page->index << huge_page_order(page_hstate(page));
353 address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); 356 address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
354 if (unlikely(address < vma->vm_start || address >= vma->vm_end)) { 357 if (unlikely(address < vma->vm_start || address >= vma->vm_end)) {
355 /* page should be within @vma mapping range */ 358 /* page should be within @vma mapping range */
@@ -394,6 +397,12 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm,
394 pte_t *pte; 397 pte_t *pte;
395 spinlock_t *ptl; 398 spinlock_t *ptl;
396 399
400 if (unlikely(PageHuge(page))) {
401 pte = huge_pte_offset(mm, address);
402 ptl = &mm->page_table_lock;
403 goto check;
404 }
405
397 pgd = pgd_offset(mm, address); 406 pgd = pgd_offset(mm, address);
398 if (!pgd_present(*pgd)) 407 if (!pgd_present(*pgd))
399 return NULL; 408 return NULL;
@@ -414,6 +423,7 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm,
414 } 423 }
415 424
416 ptl = pte_lockptr(mm, pmd); 425 ptl = pte_lockptr(mm, pmd);
426check:
417 spin_lock(ptl); 427 spin_lock(ptl);
418 if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) { 428 if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) {
419 *ptlp = ptl; 429 *ptlp = ptl;
@@ -916,6 +926,12 @@ void page_remove_rmap(struct page *page)
916 page_clear_dirty(page); 926 page_clear_dirty(page);
917 set_page_dirty(page); 927 set_page_dirty(page);
918 } 928 }
929 /*
930 * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED
931 * and not charged by memcg for now.
932 */
933 if (unlikely(PageHuge(page)))
934 return;
919 if (PageAnon(page)) { 935 if (PageAnon(page)) {
920 mem_cgroup_uncharge_page(page); 936 mem_cgroup_uncharge_page(page);
921 __dec_zone_page_state(page, NR_ANON_PAGES); 937 __dec_zone_page_state(page, NR_ANON_PAGES);
@@ -1524,3 +1540,46 @@ int rmap_walk(struct page *page, int (*rmap_one)(struct page *,
1524 return rmap_walk_file(page, rmap_one, arg); 1540 return rmap_walk_file(page, rmap_one, arg);
1525} 1541}
1526#endif /* CONFIG_MIGRATION */ 1542#endif /* CONFIG_MIGRATION */
1543
1544#ifdef CONFIG_HUGETLB_PAGE
1545/*
1546 * The following three functions are for anonymous (private mapped) hugepages.
1547 * Unlike common anonymous pages, anonymous hugepages have no accounting code
1548 * and no lru code, because we handle hugepages differently from common pages.
1549 */
1550static void __hugepage_set_anon_rmap(struct page *page,
1551 struct vm_area_struct *vma, unsigned long address, int exclusive)
1552{
1553 struct anon_vma *anon_vma = vma->anon_vma;
1554 BUG_ON(!anon_vma);
1555 if (!exclusive) {
1556 struct anon_vma_chain *avc;
1557 avc = list_entry(vma->anon_vma_chain.prev,
1558 struct anon_vma_chain, same_vma);
1559 anon_vma = avc->anon_vma;
1560 }
1561 anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
1562 page->mapping = (struct address_space *) anon_vma;
1563 page->index = linear_page_index(vma, address);
1564}
1565
1566void hugepage_add_anon_rmap(struct page *page,
1567 struct vm_area_struct *vma, unsigned long address)
1568{
1569 struct anon_vma *anon_vma = vma->anon_vma;
1570 int first;
1571 BUG_ON(!anon_vma);
1572 BUG_ON(address < vma->vm_start || address >= vma->vm_end);
1573 first = atomic_inc_and_test(&page->_mapcount);
1574 if (first)
1575 __hugepage_set_anon_rmap(page, vma, address, 0);
1576}
1577
1578void hugepage_add_new_anon_rmap(struct page *page,
1579 struct vm_area_struct *vma, unsigned long address)
1580{
1581 BUG_ON(address < vma->vm_start || address >= vma->vm_end);
1582 atomic_set(&page->_mapcount, 0);
1583 __hugepage_set_anon_rmap(page, vma, address, 1);
1584}
1585#endif /* CONFIG_HUGETLB_PAGE */