NFS: Cleanup nfs_set_port
[safe/jmp/linux-2.6] / mm / rmap.c
index f6e85d7..0383acf 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;
 
@@ -182,7 +184,9 @@ static void page_unlock_anon_vma(struct anon_vma *anon_vma)
 }
 
 /*
- * At what user virtual address is page expected in vma?
+ * At what user virtual address is page expected in @vma?
+ * Returns virtual address or -EFAULT if page's index/offset is not
+ * within the range mapped the @vma.
  */
 static inline unsigned long
 vma_address(struct page *page, struct vm_area_struct *vma)
@@ -192,8 +196,7 @@ vma_address(struct page *page, struct vm_area_struct *vma)
 
        address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
        if (unlikely(address < vma->vm_start || address >= vma->vm_end)) {
-               /* page should be within any vma from prio_tree_next */
-               BUG_ON(!PageAnon(page));
+               /* page should be within @vma mapping range */
                return -EFAULT;
        }
        return address;
@@ -221,10 +224,14 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
 /*
  * Check that @page is mapped at @address into @mm.
  *
+ * If @sync is false, page_check_address may perform a racy check to avoid
+ * the page table lock when the pte is not present (helpful when reclaiming
+ * highly shared pages).
+ *
  * On success returns with pte mapped and locked.
  */
 pte_t *page_check_address(struct page *page, struct mm_struct *mm,
-                         unsigned long address, spinlock_t **ptlp)
+                         unsigned long address, spinlock_t **ptlp, int sync)
 {
        pgd_t *pgd;
        pud_t *pud;
@@ -246,7 +253,7 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm,
 
        pte = pte_offset_map(pmd, address);
        /* Make a quick check before getting the lock */
-       if (!pte_present(*pte)) {
+       if (!sync && !pte_present(*pte)) {
                pte_unmap(pte);
                return NULL;
        }
@@ -278,11 +285,14 @@ static int page_referenced_one(struct page *page,
        if (address == -EFAULT)
                goto out;
 
-       pte = page_check_address(page, mm, address, &ptl);
+       pte = page_check_address(page, mm, address, &ptl, 0);
        if (!pte)
                goto out;
 
-       if (ptep_clear_flush_young(vma, address, pte))
+       if (vma->vm_flags & VM_LOCKED) {
+               referenced++;
+               *mapcount = 1;  /* break early from loop */
+       } else if (ptep_clear_flush_young_notify(vma, address, pte))
                referenced++;
 
        /* Pretend the page is referenced if the task has the
@@ -297,7 +307,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;
@@ -310,6 +321,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;
@@ -322,6 +340,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
@@ -330,7 +349,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;
@@ -363,6 +383,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++;
@@ -381,33 +408,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;
 }
 
@@ -423,7 +454,7 @@ static int page_mkclean_one(struct page *page, struct vm_area_struct *vma)
        if (address == -EFAULT)
                goto out;
 
-       pte = page_check_address(page, mm, address, &ptl);
+       pte = page_check_address(page, mm, address, &ptl, 1);
        if (!pte)
                goto out;
 
@@ -431,7 +462,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);
@@ -469,11 +500,12 @@ int page_mkclean(struct page *page)
 
        if (page_mapped(page)) {
                struct address_space *mapping = page_mapping(page);
-               if (mapping)
+               if (mapping) {
                        ret = page_mkclean_file(mapping, page);
-               if (page_test_dirty(page)) {
-                       page_clear_dirty(page);
-                       ret = 1;
+                       if (page_test_dirty(page)) {
+                               page_clear_dirty(page);
+                               ret = 1;
+                       }
                }
        }
 
@@ -482,7 +514,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
@@ -506,7 +538,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
@@ -553,7 +585,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
@@ -587,6 +619,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
@@ -606,6 +640,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.
  */
@@ -620,7 +655,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)
@@ -629,6 +663,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
@@ -637,12 +687,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);
        }
 }
 
@@ -664,7 +708,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
        if (address == -EFAULT)
                goto out;
 
-       pte = page_check_address(page, mm, address, &ptl);
+       pte = page_check_address(page, mm, address, &ptl, 0);
        if (!pte)
                goto out;
 
@@ -674,14 +718,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))
@@ -806,12 +850,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))
@@ -852,6 +896,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.
@@ -948,6 +993,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.