mm: fix hang on anon_vma->root->lock
[linux-2.6.git] / mm / rmap.c
index f5d6799..f6f0d2d 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -56,6 +56,7 @@
 #include <linux/memcontrol.h>
 #include <linux/mmu_notifier.h>
 #include <linux/migrate.h>
+#include <linux/hugetlb.h>
 
 #include <asm/tlbflush.h>
 
@@ -315,7 +316,7 @@ void __init anon_vma_init(void)
  */
 struct anon_vma *page_lock_anon_vma(struct page *page)
 {
-       struct anon_vma *anon_vma;
+       struct anon_vma *anon_vma, *root_anon_vma;
        unsigned long anon_mapping;
 
        rcu_read_lock();
@@ -326,8 +327,21 @@ struct anon_vma *page_lock_anon_vma(struct page *page)
                goto out;
 
        anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
-       anon_vma_lock(anon_vma);
-       return anon_vma;
+       root_anon_vma = ACCESS_ONCE(anon_vma->root);
+       spin_lock(&root_anon_vma->lock);
+
+       /*
+        * If this page is still mapped, then its anon_vma cannot have been
+        * freed.  But if it has been unmapped, we have no security against
+        * the anon_vma structure being freed and reused (for another anon_vma:
+        * SLAB_DESTROY_BY_RCU guarantees that - so the spin_lock above cannot
+        * corrupt): with anon_vma_prepare() or anon_vma_fork() redirecting
+        * anon_vma->root before page_unlock_anon_vma() is called to unlock.
+        */
+       if (page_mapped(page))
+               return anon_vma;
+
+       spin_unlock(&root_anon_vma->lock);
 out:
        rcu_read_unlock();
        return NULL;
@@ -350,6 +364,8 @@ vma_address(struct page *page, struct vm_area_struct *vma)
        pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
        unsigned long address;
 
+       if (unlikely(is_vm_hugetlb_page(vma)))
+               pgoff = page->index << huge_page_order(page_hstate(page));
        address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
        if (unlikely(address < vma->vm_start || address >= vma->vm_end)) {
                /* page should be within @vma mapping range */
@@ -364,9 +380,10 @@ vma_address(struct page *page, struct vm_area_struct *vma)
  */
 unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
 {
-       if (PageAnon(page))
-               ;
-       else if (page->mapping && !(vma->vm_flags & VM_NONLINEAR)) {
+       if (PageAnon(page)) {
+               if (vma->anon_vma->root != page_anon_vma(page)->root)
+                       return -EFAULT;
+       } else if (page->mapping && !(vma->vm_flags & VM_NONLINEAR)) {
                if (!vma->vm_file ||
                    vma->vm_file->f_mapping != page->mapping)
                        return -EFAULT;
@@ -393,6 +410,12 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm,
        pte_t *pte;
        spinlock_t *ptl;
 
+       if (unlikely(PageHuge(page))) {
+               pte = huge_pte_offset(mm, address);
+               ptl = &mm->page_table_lock;
+               goto check;
+       }
+
        pgd = pgd_offset(mm, address);
        if (!pgd_present(*pgd))
                return NULL;
@@ -413,6 +436,7 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm,
        }
 
        ptl = pte_lockptr(mm, pmd);
+check:
        spin_lock(ptl);
        if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) {
                *ptlp = ptl;
@@ -810,6 +834,7 @@ static void __page_check_anon_rmap(struct page *page,
         * are initially only visible via the pagetables, and the pte is locked
         * over the call to page_add_new_anon_rmap.
         */
+       BUG_ON(page_anon_vma(page)->root != vma->anon_vma->root);
        BUG_ON(page->index != linear_page_index(vma, address));
 #endif
 }
@@ -828,6 +853,17 @@ static void __page_check_anon_rmap(struct page *page,
 void page_add_anon_rmap(struct page *page,
        struct vm_area_struct *vma, unsigned long address)
 {
+       do_page_add_anon_rmap(page, vma, address, 0);
+}
+
+/*
+ * Special version of the above for do_swap_page, which often runs
+ * into pages that are exclusively owned by the current process.
+ * Everybody else should continue to use page_add_anon_rmap above.
+ */
+void do_page_add_anon_rmap(struct page *page,
+       struct vm_area_struct *vma, unsigned long address, int exclusive)
+{
        int first = atomic_inc_and_test(&page->_mapcount);
        if (first)
                __inc_zone_page_state(page, NR_ANON_PAGES);
@@ -837,7 +873,7 @@ void page_add_anon_rmap(struct page *page,
        VM_BUG_ON(!PageLocked(page));
        VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end);
        if (first)
-               __page_set_anon_rmap(page, vma, address, 0);
+               __page_set_anon_rmap(page, vma, address, exclusive);
        else
                __page_check_anon_rmap(page, vma, address);
 }
@@ -903,6 +939,12 @@ void page_remove_rmap(struct page *page)
                page_clear_dirty(page);
                set_page_dirty(page);
        }
+       /*
+        * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED
+        * and not charged by memcg for now.
+        */
+       if (unlikely(PageHuge(page)))
+               return;
        if (PageAnon(page)) {
                mem_cgroup_uncharge_page(page);
                __dec_zone_page_state(page, NR_ANON_PAGES);
@@ -1407,6 +1449,7 @@ int try_to_munlock(struct page *page)
  */
 void drop_anon_vma(struct anon_vma *anon_vma)
 {
+       BUG_ON(atomic_read(&anon_vma->external_refcount) <= 0);
        if (atomic_dec_and_lock(&anon_vma->external_refcount, &anon_vma->root->lock)) {
                struct anon_vma *root = anon_vma->root;
                int empty = list_empty(&anon_vma->head);
@@ -1418,6 +1461,7 @@ void drop_anon_vma(struct anon_vma *anon_vma)
                 * the refcount on the root and check if we need to free it.
                 */
                if (empty && anon_vma != root) {
+                       BUG_ON(atomic_read(&root->external_refcount) <= 0);
                        last_root_user = atomic_dec_and_test(&root->external_refcount);
                        root_empty = list_empty(&root->head);
                }
@@ -1509,3 +1553,46 @@ int rmap_walk(struct page *page, int (*rmap_one)(struct page *,
                return rmap_walk_file(page, rmap_one, arg);
 }
 #endif /* CONFIG_MIGRATION */
+
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * The following three functions are for anonymous (private mapped) hugepages.
+ * Unlike common anonymous pages, anonymous hugepages have no accounting code
+ * and no lru code, because we handle hugepages differently from common pages.
+ */
+static void __hugepage_set_anon_rmap(struct page *page,
+       struct vm_area_struct *vma, unsigned long address, int exclusive)
+{
+       struct anon_vma *anon_vma = vma->anon_vma;
+       BUG_ON(!anon_vma);
+       if (!exclusive) {
+               struct anon_vma_chain *avc;
+               avc = list_entry(vma->anon_vma_chain.prev,
+                                struct anon_vma_chain, same_vma);
+               anon_vma = avc->anon_vma;
+       }
+       anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
+       page->mapping = (struct address_space *) anon_vma;
+       page->index = linear_page_index(vma, address);
+}
+
+void hugepage_add_anon_rmap(struct page *page,
+                           struct vm_area_struct *vma, unsigned long address)
+{
+       struct anon_vma *anon_vma = vma->anon_vma;
+       int first;
+       BUG_ON(!anon_vma);
+       BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+       first = atomic_inc_and_test(&page->_mapcount);
+       if (first)
+               __hugepage_set_anon_rmap(page, vma, address, 0);
+}
+
+void hugepage_add_new_anon_rmap(struct page *page,
+                       struct vm_area_struct *vma, unsigned long address)
+{
+       BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+       atomic_set(&page->_mapcount, 0);
+       __hugepage_set_anon_rmap(page, vma, address, 1);
+}
+#endif /* CONFIG_HUGETLB_PAGE */