mm: page_remove_rmap comments on PageAnon
[safe/jmp/linux-2.6] / mm / rmap.c
index 57ad276..0597747 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -48,6 +48,8 @@
 #include <linux/rcupdate.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/memcontrol.h>
+#include <linux/mmu_notifier.h>
 
 #include <asm/tlbflush.h>
 
@@ -137,7 +139,7 @@ void anon_vma_unlink(struct vm_area_struct *vma)
                anon_vma_free(anon_vma);
 }
 
-static void anon_vma_ctor(struct kmem_cache *cachep, void *data)
+static void anon_vma_ctor(void *data)
 {
        struct anon_vma *anon_vma = data;
 
@@ -286,7 +288,7 @@ static int page_referenced_one(struct page *page,
        if (vma->vm_flags & VM_LOCKED) {
                referenced++;
                *mapcount = 1;  /* break early from loop */
-       } else if (ptep_clear_flush_young(vma, address, pte))
+       } else if (ptep_clear_flush_young_notify(vma, address, pte))
                referenced++;
 
        /* Pretend the page is referenced if the task has the
@@ -301,7 +303,8 @@ out:
        return referenced;
 }
 
-static int page_referenced_anon(struct page *page)
+static int page_referenced_anon(struct page *page,
+                               struct mem_cgroup *mem_cont)
 {
        unsigned int mapcount;
        struct anon_vma *anon_vma;
@@ -314,6 +317,13 @@ static int page_referenced_anon(struct page *page)
 
        mapcount = page_mapcount(page);
        list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
+               /*
+                * If we are reclaiming on behalf of a cgroup, skip
+                * counting on behalf of references from different
+                * cgroups
+                */
+               if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
+                       continue;
                referenced += page_referenced_one(page, vma, &mapcount);
                if (!mapcount)
                        break;
@@ -326,6 +336,7 @@ static int page_referenced_anon(struct page *page)
 /**
  * page_referenced_file - referenced check for object-based rmap
  * @page: the page we're checking references on.
+ * @mem_cont: target memory controller
  *
  * For an object-based mapped page, find all the places it is mapped and
  * check/clear the referenced flag.  This is done by following the page->mapping
@@ -334,7 +345,8 @@ static int page_referenced_anon(struct page *page)
  *
  * This function is only called from page_referenced for object-based pages.
  */
-static int page_referenced_file(struct page *page)
+static int page_referenced_file(struct page *page,
+                               struct mem_cgroup *mem_cont)
 {
        unsigned int mapcount;
        struct address_space *mapping = page->mapping;
@@ -367,6 +379,13 @@ static int page_referenced_file(struct page *page)
        mapcount = page_mapcount(page);
 
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
+               /*
+                * If we are reclaiming on behalf of a cgroup, skip
+                * counting on behalf of references from different
+                * cgroups
+                */
+               if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
+                       continue;
                if ((vma->vm_flags & (VM_LOCKED|VM_MAYSHARE))
                                  == (VM_LOCKED|VM_MAYSHARE)) {
                        referenced++;
@@ -385,33 +404,37 @@ static int page_referenced_file(struct page *page)
  * page_referenced - test if the page was referenced
  * @page: the page to test
  * @is_locked: caller holds lock on the page
+ * @mem_cont: target memory controller
  *
  * Quick test_and_clear_referenced for all mappings to a page,
  * returns the number of ptes which referenced the page.
  */
-int page_referenced(struct page *page, int is_locked)
+int page_referenced(struct page *page, int is_locked,
+                       struct mem_cgroup *mem_cont)
 {
        int referenced = 0;
 
-       if (page_test_and_clear_young(page))
-               referenced++;
-
        if (TestClearPageReferenced(page))
                referenced++;
 
        if (page_mapped(page) && page->mapping) {
                if (PageAnon(page))
-                       referenced += page_referenced_anon(page);
+                       referenced += page_referenced_anon(page, mem_cont);
                else if (is_locked)
-                       referenced += page_referenced_file(page);
-               else if (TestSetPageLocked(page))
+                       referenced += page_referenced_file(page, mem_cont);
+               else if (!trylock_page(page))
                        referenced++;
                else {
                        if (page->mapping)
-                               referenced += page_referenced_file(page);
+                               referenced +=
+                                       page_referenced_file(page, mem_cont);
                        unlock_page(page);
                }
        }
+
+       if (page_test_and_clear_young(page))
+               referenced++;
+
        return referenced;
 }
 
@@ -435,7 +458,7 @@ static int page_mkclean_one(struct page *page, struct vm_area_struct *vma)
                pte_t entry;
 
                flush_cache_page(vma, address, pte_pfn(*pte));
-               entry = ptep_clear_flush(vma, address, pte);
+               entry = ptep_clear_flush_notify(vma, address, pte);
                entry = pte_wrprotect(entry);
                entry = pte_mkclean(entry);
                set_pte_at(mm, address, pte, entry);
@@ -487,7 +510,7 @@ int page_mkclean(struct page *page)
 EXPORT_SYMBOL_GPL(page_mkclean);
 
 /**
- * page_set_anon_rmap - setup new anonymous rmap
+ * __page_set_anon_rmap - setup new anonymous rmap
  * @page:      the page to add the mapping to
  * @vma:       the vm area in which the mapping is added
  * @address:   the user virtual address mapped
@@ -511,7 +534,7 @@ static void __page_set_anon_rmap(struct page *page,
 }
 
 /**
- * page_set_anon_rmap - sanity check anonymous rmap addition
+ * __page_check_anon_rmap - sanity check anonymous rmap addition
  * @page:      the page to add the mapping to
  * @vma:       the vm area in which the mapping is added
  * @address:   the user virtual address mapped
@@ -558,7 +581,7 @@ void page_add_anon_rmap(struct page *page,
                __page_check_anon_rmap(page, vma, address);
 }
 
-/*
+/**
  * page_add_new_anon_rmap - add pte mapping to a new anonymous page
  * @page:      the page to add the mapping to
  * @vma:       the vm area in which the mapping is added
@@ -592,6 +615,8 @@ void page_add_file_rmap(struct page *page)
 /**
  * page_dup_rmap - duplicate pte mapping to a page
  * @page:      the page to add the mapping to
+ * @vma:       the vm area being duplicated
+ * @address:   the user virtual address mapped
  *
  * For copy_page_range only: minimal extract from page_add_file_rmap /
  * page_add_anon_rmap, avoiding unnecessary tests (already checked) so it's
@@ -611,6 +636,7 @@ void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long
 /**
  * page_remove_rmap - take down pte mapping from a page
  * @page: page to remove mapping from
+ * @vma: the vm area in which the mapping is removed
  *
  * The caller needs to hold the pte lock.
  */
@@ -625,7 +651,6 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
                        printk (KERN_EMERG "  page->mapping = %p\n", page->mapping);
                        print_symbol (KERN_EMERG "  vma->vm_ops = %s\n", (unsigned long)vma->vm_ops);
                        if (vma->vm_ops) {
-                               print_symbol (KERN_EMERG "  vma->vm_ops->nopage = %s\n", (unsigned long)vma->vm_ops->nopage);
                                print_symbol (KERN_EMERG "  vma->vm_ops->fault = %s\n", (unsigned long)vma->vm_ops->fault);
                        }
                        if (vma->vm_file && vma->vm_file->f_op)
@@ -634,6 +659,22 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
                }
 
                /*
+                * Now that the last pte has gone, s390 must transfer dirty
+                * flag from storage key to struct page.  We can usually skip
+                * this if the page is anon, so about to be freed; but perhaps
+                * not if it's in swapcache - there might be another pte slot
+                * containing the swap entry, but page not yet written to swap.
+                */
+               if ((!PageAnon(page) || PageSwapCache(page)) &&
+                   page_test_dirty(page)) {
+                       page_clear_dirty(page);
+                       set_page_dirty(page);
+               }
+
+               mem_cgroup_uncharge_page(page);
+               __dec_zone_page_state(page,
+                       PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED);
+               /*
                 * It would be tidy to reset the PageAnon mapping here,
                 * but that might overwrite a racing page_add_anon_rmap
                 * which increments mapcount after us but sets mapping
@@ -642,12 +683,6 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
                 * Leaving it set also helps swapoff to reinstate ptes
                 * faster for those pages still in swapcache.
                 */
-               if (page_test_dirty(page)) {
-                       page_clear_dirty(page);
-                       set_page_dirty(page);
-               }
-               __dec_zone_page_state(page,
-                               PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED);
        }
 }
 
@@ -679,14 +714,14 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
         * skipped over this mm) then we should reactivate it.
         */
        if (!migration && ((vma->vm_flags & VM_LOCKED) ||
-                       (ptep_clear_flush_young(vma, address, pte)))) {
+                       (ptep_clear_flush_young_notify(vma, address, pte)))) {
                ret = SWAP_FAIL;
                goto out_unmap;
        }
 
        /* Nuke the page table entry. */
        flush_cache_page(vma, address, page_to_pfn(page));
-       pteval = ptep_clear_flush(vma, address, pte);
+       pteval = ptep_clear_flush_notify(vma, address, pte);
 
        /* Move the dirty bit to the physical page now the pte is gone. */
        if (pte_dirty(pteval))
@@ -811,12 +846,12 @@ static void try_to_unmap_cluster(unsigned long cursor,
                page = vm_normal_page(vma, address, *pte);
                BUG_ON(!page || PageAnon(page));
 
-               if (ptep_clear_flush_young(vma, address, pte))
+               if (ptep_clear_flush_young_notify(vma, address, pte))
                        continue;
 
                /* Nuke the page table entry. */
                flush_cache_page(vma, address, pte_pfn(*pte));
-               pteval = ptep_clear_flush(vma, address, pte);
+               pteval = ptep_clear_flush_notify(vma, address, pte);
 
                /* If nonlinear, store the file page offset in the pte. */
                if (page->index != linear_page_index(vma, address))
@@ -857,6 +892,7 @@ static int try_to_unmap_anon(struct page *page, int migration)
 /**
  * try_to_unmap_file - unmap file page using the object-based rmap method
  * @page: the page to unmap
+ * @migration: migration flag
  *
  * Find all the mappings of a page using the mapping pointer and the vma chains
  * contained in the address_space struct it points to.
@@ -953,6 +989,7 @@ out:
 /**
  * try_to_unmap - try to remove all page table mappings to a page
  * @page: the page to get unmapped
+ * @migration: migration flag
  *
  * Tries to remove all the page table entries which are mapping this
  * page, used in the pageout path.  Caller must hold the page lock.