SL*B: drop kmem cache argument from constructor
[linux-2.6.git] / mm / rmap.c
index d8a842a..39ae5a9 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
 #include <linux/rmap.h>
 #include <linux/rcupdate.h>
 #include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/memcontrol.h>
 
 #include <asm/tlbflush.h>
 
 struct kmem_cache *anon_vma_cachep;
 
-static inline void validate_anon_vma(struct vm_area_struct *find_vma)
-{
-#ifdef CONFIG_DEBUG_VM
-       struct anon_vma *anon_vma = find_vma->anon_vma;
-       struct vm_area_struct *vma;
-       unsigned int mapcount = 0;
-       int found = 0;
-
-       list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
-               mapcount++;
-               BUG_ON(mapcount > 100000);
-               if (vma == find_vma)
-                       found = 1;
-       }
-       BUG_ON(!found);
-#endif
-}
-
 /* This must be called under the mmap_sem. */
 int anon_vma_prepare(struct vm_area_struct *vma)
 {
@@ -120,10 +104,8 @@ void __anon_vma_link(struct vm_area_struct *vma)
 {
        struct anon_vma *anon_vma = vma->anon_vma;
 
-       if (anon_vma) {
+       if (anon_vma)
                list_add_tail(&vma->anon_vma_node, &anon_vma->head);
-               validate_anon_vma(vma);
-       }
 }
 
 void anon_vma_link(struct vm_area_struct *vma)
@@ -133,7 +115,6 @@ void anon_vma_link(struct vm_area_struct *vma)
        if (anon_vma) {
                spin_lock(&anon_vma->lock);
                list_add_tail(&vma->anon_vma_node, &anon_vma->head);
-               validate_anon_vma(vma);
                spin_unlock(&anon_vma->lock);
        }
 }
@@ -147,7 +128,6 @@ void anon_vma_unlink(struct vm_area_struct *vma)
                return;
 
        spin_lock(&anon_vma->lock);
-       validate_anon_vma(vma);
        list_del(&vma->anon_vma_node);
 
        /* We must garbage collect the anon_vma if it's empty */
@@ -158,22 +138,18 @@ void anon_vma_unlink(struct vm_area_struct *vma)
                anon_vma_free(anon_vma);
 }
 
-static void anon_vma_ctor(void *data, struct kmem_cache *cachep,
-                         unsigned long flags)
+static void anon_vma_ctor(void *data)
 {
-       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-                                               SLAB_CTOR_CONSTRUCTOR) {
-               struct anon_vma *anon_vma = data;
+       struct anon_vma *anon_vma = data;
 
-               spin_lock_init(&anon_vma->lock);
-               INIT_LIST_HEAD(&anon_vma->head);
-       }
+       spin_lock_init(&anon_vma->lock);
+       INIT_LIST_HEAD(&anon_vma->head);
 }
 
 void __init anon_vma_init(void)
 {
        anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma),
-                       0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor, NULL);
+                       0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor);
 }
 
 /*
@@ -182,7 +158,7 @@ void __init anon_vma_init(void)
  */
 static struct anon_vma *page_lock_anon_vma(struct page *page)
 {
-       struct anon_vma *anon_vma = NULL;
+       struct anon_vma *anon_vma;
        unsigned long anon_mapping;
 
        rcu_read_lock();
@@ -194,13 +170,22 @@ static struct anon_vma *page_lock_anon_vma(struct page *page)
 
        anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
        spin_lock(&anon_vma->lock);
+       return anon_vma;
 out:
        rcu_read_unlock();
-       return anon_vma;
+       return NULL;
+}
+
+static void page_unlock_anon_vma(struct anon_vma *anon_vma)
+{
+       spin_unlock(&anon_vma->lock);
+       rcu_read_unlock();
 }
 
 /*
- * 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)
@@ -210,8 +195,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;
@@ -300,7 +284,10 @@ static int page_referenced_one(struct page *page,
        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(vma, address, pte))
                referenced++;
 
        /* Pretend the page is referenced if the task has the
@@ -315,7 +302,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;
@@ -328,17 +316,26 @@ 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;
        }
-       spin_unlock(&anon_vma->lock);
+
+       page_unlock_anon_vma(anon_vma);
        return referenced;
 }
 
 /**
  * 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
@@ -347,7 +344,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;
@@ -380,6 +378,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++;
@@ -398,33 +403,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);
+                       referenced += page_referenced_file(page, mem_cont);
                else if (TestSetPageLocked(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;
 }
 
@@ -432,7 +441,7 @@ static int page_mkclean_one(struct page *page, struct vm_area_struct *vma)
 {
        struct mm_struct *mm = vma->vm_mm;
        unsigned long address;
-       pte_t *pte, entry;
+       pte_t *pte;
        spinlock_t *ptl;
        int ret = 0;
 
@@ -444,17 +453,17 @@ static int page_mkclean_one(struct page *page, struct vm_area_struct *vma)
        if (!pte)
                goto out;
 
-       if (!pte_dirty(*pte) && !pte_write(*pte))
-               goto unlock;
+       if (pte_dirty(*pte) || pte_write(*pte)) {
+               pte_t entry;
 
-       entry = ptep_get_and_clear(mm, address, pte);
-       entry = pte_mkclean(entry);
-       entry = pte_wrprotect(entry);
-       ptep_establish(vma, address, pte, entry);
-       lazy_mmu_prot_update(entry);
-       ret = 1;
+               flush_cache_page(vma, address, pte_pfn(*pte));
+               entry = ptep_clear_flush(vma, address, pte);
+               entry = pte_wrprotect(entry);
+               entry = pte_mkclean(entry);
+               set_pte_at(mm, address, pte, entry);
+               ret = 1;
+       }
 
-unlock:
        pte_unmap_unlock(pte, ptl);
 out:
        return ret;
@@ -486,15 +495,21 @@ 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;
+                       }
+               }
        }
 
        return ret;
 }
+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
@@ -518,22 +533,54 @@ static void __page_set_anon_rmap(struct page *page,
 }
 
 /**
+ * __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
+ */
+static void __page_check_anon_rmap(struct page *page,
+       struct vm_area_struct *vma, unsigned long address)
+{
+#ifdef CONFIG_DEBUG_VM
+       /*
+        * The page's anon-rmap details (mapping and index) are guaranteed to
+        * be set up correctly at this point.
+        *
+        * We have exclusion against page_add_anon_rmap because the caller
+        * always holds the page locked, except if called from page_dup_rmap,
+        * in which case the page is already known to be setup.
+        *
+        * We have exclusion against page_add_new_anon_rmap because those pages
+        * are initially only visible via the pagetables, and the pte is locked
+        * over the call to page_add_new_anon_rmap.
+        */
+       struct anon_vma *anon_vma = vma->anon_vma;
+       anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
+       BUG_ON(page->mapping != (struct address_space *)anon_vma);
+       BUG_ON(page->index != linear_page_index(vma, address));
+#endif
+}
+
+/**
  * page_add_anon_rmap - add pte mapping to an anonymous page
  * @page:      the page to add the mapping to
  * @vma:       the vm area in which the mapping is added
  * @address:   the user virtual address mapped
  *
- * The caller needs to hold the pte lock.
+ * The caller needs to hold the pte lock and the page must be locked.
  */
 void page_add_anon_rmap(struct page *page,
        struct vm_area_struct *vma, unsigned long address)
 {
+       VM_BUG_ON(!PageLocked(page));
+       VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end);
        if (atomic_inc_and_test(&page->_mapcount))
                __page_set_anon_rmap(page, vma, address);
-       /* else checking page index and mapping is racy */
+       else
+               __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
@@ -541,10 +588,12 @@ void page_add_anon_rmap(struct page *page,
  *
  * Same as page_add_anon_rmap but must only be called on *new* pages.
  * This means the inc-and-test can be bypassed.
+ * Page does not have to be locked.
  */
 void page_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); /* elevate count by 1 (starts at -1) */
        __page_set_anon_rmap(page, vma, address);
 }
@@ -561,20 +610,50 @@ void page_add_file_rmap(struct page *page)
                __inc_zone_page_state(page, NR_FILE_MAPPED);
 }
 
+#ifdef CONFIG_DEBUG_VM
+/**
+ * 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
+ * quicker.
+ *
+ * The caller needs to hold the pte lock.
+ */
+void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address)
+{
+       BUG_ON(page_mapcount(page) == 0);
+       if (PageAnon(page))
+               __page_check_anon_rmap(page, vma, address);
+       atomic_inc(&page->_mapcount);
+}
+#endif
+
 /**
  * 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.
  */
-void page_remove_rmap(struct page *page)
+void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
 {
        if (atomic_add_negative(-1, &page->_mapcount)) {
                if (unlikely(page_mapcount(page) < 0)) {
                        printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page));
+                       printk (KERN_EMERG "  page pfn = %lx\n", page_to_pfn(page));
                        printk (KERN_EMERG "  page->flags = %lx\n", page->flags);
                        printk (KERN_EMERG "  page->count = %x\n", page_count(page));
                        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->fault = %s\n", (unsigned long)vma->vm_ops->fault);
+                       }
+                       if (vma->vm_file && vma->vm_file->f_op)
+                               print_symbol (KERN_EMERG "  vma->vm_file->f_op->mmap = %s\n", (unsigned long)vma->vm_file->f_op->mmap);
                        BUG();
                }
 
@@ -587,8 +666,12 @@ void page_remove_rmap(struct page *page)
                 * Leaving it set also helps swapoff to reinstate ptes
                 * faster for those pages still in swapcache.
                 */
-               if (page_test_and_clear_dirty(page))
+               if (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);
        }
@@ -679,7 +762,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
                dec_mm_counter(mm, file_rss);
 
 
-       page_remove_rmap(page);
+       page_remove_rmap(page, vma);
        page_cache_release(page);
 
 out_unmap:
@@ -769,7 +852,7 @@ static void try_to_unmap_cluster(unsigned long cursor,
                if (pte_dirty(pteval))
                        set_page_dirty(page);
 
-               page_remove_rmap(page);
+               page_remove_rmap(page, vma);
                page_cache_release(page);
                dec_mm_counter(mm, file_rss);
                (*mapcount)--;
@@ -792,13 +875,15 @@ static int try_to_unmap_anon(struct page *page, int migration)
                if (ret == SWAP_FAIL || !page_mapped(page))
                        break;
        }
-       spin_unlock(&anon_vma->lock);
+
+       page_unlock_anon_vma(anon_vma);
        return ret;
 }
 
 /**
  * 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.
@@ -895,6 +980,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.