vsprintf: pre-calculate final string length for later use
[safe/jmp/linux-2.6] / mm / rmap.c
index 869aaa3..98135db 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -68,7 +68,7 @@ static inline struct anon_vma *anon_vma_alloc(void)
        return kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL);
 }
 
-static inline void anon_vma_free(struct anon_vma *anon_vma)
+void anon_vma_free(struct anon_vma *anon_vma)
 {
        kmem_cache_free(anon_vma_cachep, anon_vma);
 }
@@ -172,7 +172,7 @@ void anon_vma_unlink(struct vm_area_struct *vma)
        list_del(&vma->anon_vma_node);
 
        /* We must garbage collect the anon_vma if it's empty */
-       empty = list_empty(&anon_vma->head);
+       empty = list_empty(&anon_vma->head) && !ksm_refcount(anon_vma);
        spin_unlock(&anon_vma->lock);
 
        if (empty)
@@ -184,6 +184,7 @@ static void anon_vma_ctor(void *data)
        struct anon_vma *anon_vma = data;
 
        spin_lock_init(&anon_vma->lock);
+       ksm_refcount_init(anon_vma);
        INIT_LIST_HEAD(&anon_vma->head);
 }
 
@@ -203,7 +204,7 @@ struct anon_vma *page_lock_anon_vma(struct page *page)
        unsigned long anon_mapping;
 
        rcu_read_lock();
-       anon_mapping = (unsigned long) page->mapping;
+       anon_mapping = (unsigned long) ACCESS_ONCE(page->mapping);
        if ((anon_mapping & PAGE_MAPPING_FLAGS) != PAGE_MAPPING_ANON)
                goto out;
        if (!page_mapped(page))
@@ -665,7 +666,9 @@ static void __page_check_anon_rmap(struct page *page,
  * @address:   the user virtual address mapped
  *
  * The caller needs to hold the pte lock, and the page must be locked in
- * the anon_vma case: to serialize mapping,index checking after setting.
+ * the anon_vma case: to serialize mapping,index checking after setting,
+ * and to ensure that PageAnon is not being upgraded racily to PageKsm
+ * (but PageKsm is never downgraded to PageAnon).
  */
 void page_add_anon_rmap(struct page *page,
        struct vm_area_struct *vma, unsigned long address)
@@ -786,10 +789,9 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
         * skipped over this mm) then we should reactivate it.
         */
        if (!(flags & TTU_IGNORE_MLOCK)) {
-               if (vma->vm_flags & VM_LOCKED) {
-                       ret = SWAP_MLOCK;
-                       goto out_unmap;
-               }
+               if (vma->vm_flags & VM_LOCKED)
+                       goto out_mlock;
+
                if (TTU_ACTION(flags) == TTU_MUNLOCK)
                        goto out_unmap;
        }
@@ -862,18 +864,28 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
 
 out_unmap:
        pte_unmap_unlock(pte, ptl);
+out:
+       return ret;
 
-       if (ret == SWAP_MLOCK) {
-               ret = SWAP_AGAIN;
-               if (down_read_trylock(&vma->vm_mm->mmap_sem)) {
-                       if (vma->vm_flags & VM_LOCKED) {
-                               mlock_vma_page(page);
-                               ret = SWAP_MLOCK;
-                       }
-                       up_read(&vma->vm_mm->mmap_sem);
+out_mlock:
+       pte_unmap_unlock(pte, ptl);
+
+
+       /*
+        * We need mmap_sem locking, Otherwise VM_LOCKED check makes
+        * unstable result and race. Plus, We can't wait here because
+        * we now hold anon_vma->lock or mapping->i_mmap_lock.
+        * if trylock failed, the page remain in evictable lru and later
+        * vmscan could retry to move the page to unevictable lru if the
+        * page is actually mlocked.
+        */
+       if (down_read_trylock(&vma->vm_mm->mmap_sem)) {
+               if (vma->vm_flags & VM_LOCKED) {
+                       mlock_vma_page(page);
+                       ret = SWAP_MLOCK;
                }
+               up_read(&vma->vm_mm->mmap_sem);
        }
-out:
        return ret;
 }
 
@@ -1200,3 +1212,82 @@ int try_to_munlock(struct page *page)
        else
                return try_to_unmap_file(page, TTU_MUNLOCK);
 }
+
+#ifdef CONFIG_MIGRATION
+/*
+ * rmap_walk() and its helpers rmap_walk_anon() and rmap_walk_file():
+ * Called by migrate.c to remove migration ptes, but might be used more later.
+ */
+static int rmap_walk_anon(struct page *page, int (*rmap_one)(struct page *,
+               struct vm_area_struct *, unsigned long, void *), void *arg)
+{
+       struct anon_vma *anon_vma;
+       struct vm_area_struct *vma;
+       int ret = SWAP_AGAIN;
+
+       /*
+        * Note: remove_migration_ptes() cannot use page_lock_anon_vma()
+        * because that depends on page_mapped(); but not all its usages
+        * are holding mmap_sem, which also gave the necessary guarantee
+        * (that this anon_vma's slab has not already been destroyed).
+        * This needs to be reviewed later: avoiding page_lock_anon_vma()
+        * is risky, and currently limits the usefulness of rmap_walk().
+        */
+       anon_vma = page_anon_vma(page);
+       if (!anon_vma)
+               return ret;
+       spin_lock(&anon_vma->lock);
+       list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
+               unsigned long address = vma_address(page, vma);
+               if (address == -EFAULT)
+                       continue;
+               ret = rmap_one(page, vma, address, arg);
+               if (ret != SWAP_AGAIN)
+                       break;
+       }
+       spin_unlock(&anon_vma->lock);
+       return ret;
+}
+
+static int rmap_walk_file(struct page *page, int (*rmap_one)(struct page *,
+               struct vm_area_struct *, unsigned long, void *), void *arg)
+{
+       struct address_space *mapping = page->mapping;
+       pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+       struct vm_area_struct *vma;
+       struct prio_tree_iter iter;
+       int ret = SWAP_AGAIN;
+
+       if (!mapping)
+               return ret;
+       spin_lock(&mapping->i_mmap_lock);
+       vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
+               unsigned long address = vma_address(page, vma);
+               if (address == -EFAULT)
+                       continue;
+               ret = rmap_one(page, vma, address, arg);
+               if (ret != SWAP_AGAIN)
+                       break;
+       }
+       /*
+        * No nonlinear handling: being always shared, nonlinear vmas
+        * never contain migration ptes.  Decide what to do about this
+        * limitation to linear when we need rmap_walk() on nonlinear.
+        */
+       spin_unlock(&mapping->i_mmap_lock);
+       return ret;
+}
+
+int rmap_walk(struct page *page, int (*rmap_one)(struct page *,
+               struct vm_area_struct *, unsigned long, void *), void *arg)
+{
+       VM_BUG_ON(!PageLocked(page));
+
+       if (unlikely(PageKsm(page)))
+               return rmap_walk_ksm(page, rmap_one, arg);
+       else if (PageAnon(page))
+               return rmap_walk_anon(page, rmap_one, arg);
+       else
+               return rmap_walk_file(page, rmap_one, arg);
+}
+#endif /* CONFIG_MIGRATION */