mm/rmap: use rmap_walk() in try_to_munlock()
authorJoonsoo Kim <iamjoonsoo.kim@lge.com>
Tue, 21 Jan 2014 23:49:52 +0000 (15:49 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Jan 2014 00:19:45 +0000 (16:19 -0800)
Now, we have an infrastructure in rmap_walk() to handle difference from
variants of rmap traversing functions.

So, just use it in try_to_munlock().

In this patch, I change following things.

1. remove some variants of rmap traversing functions.
cf> try_to_unmap_ksm, try_to_unmap_anon, try_to_unmap_file
2. mechanical change to use rmap_walk() in try_to_munlock().
3. copy and paste comments.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Hugh Dickins <hughd@google.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Hillf Danton <dhillf@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/ksm.h
mm/ksm.c
mm/rmap.c

index 0eef8cb0baf72be865e20f311c0121ec8200be88..91b9719722c3765eb12eeba2882acf02cc38a78c 100644 (file)
@@ -75,7 +75,6 @@ struct page *ksm_might_need_to_copy(struct page *page,
 
 int page_referenced_ksm(struct page *page,
                        struct mem_cgroup *memcg, unsigned long *vm_flags);
-int try_to_unmap_ksm(struct page *page, enum ttu_flags flags);
 int rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc);
 void ksm_migrate_page(struct page *newpage, struct page *oldpage);
 
@@ -114,11 +113,6 @@ static inline int page_referenced_ksm(struct page *page,
        return 0;
 }
 
-static inline int try_to_unmap_ksm(struct page *page, enum ttu_flags flags)
-{
-       return 0;
-}
-
 static inline int rmap_walk_ksm(struct page *page,
                        struct rmap_walk_control *rwc)
 {
index 6b4baa97f4c010bb2c2f2953b9eda9a0b5adfced..646d45a6b6c8404ddee0cefe7bad144d6acecdcc 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1946,56 +1946,6 @@ out:
        return referenced;
 }
 
-int try_to_unmap_ksm(struct page *page, enum ttu_flags flags)
-{
-       struct stable_node *stable_node;
-       struct rmap_item *rmap_item;
-       int ret = SWAP_AGAIN;
-       int search_new_forks = 0;
-
-       VM_BUG_ON(!PageKsm(page));
-       VM_BUG_ON(!PageLocked(page));
-
-       stable_node = page_stable_node(page);
-       if (!stable_node)
-               return SWAP_FAIL;
-again:
-       hlist_for_each_entry(rmap_item, &stable_node->hlist, hlist) {
-               struct anon_vma *anon_vma = rmap_item->anon_vma;
-               struct anon_vma_chain *vmac;
-               struct vm_area_struct *vma;
-
-               anon_vma_lock_read(anon_vma);
-               anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
-                                              0, ULONG_MAX) {
-                       vma = vmac->vma;
-                       if (rmap_item->address < vma->vm_start ||
-                           rmap_item->address >= vma->vm_end)
-                               continue;
-                       /*
-                        * Initially we examine only the vma which covers this
-                        * rmap_item; but later, if there is still work to do,
-                        * we examine covering vmas in other mms: in case they
-                        * were forked from the original since ksmd passed.
-                        */
-                       if ((rmap_item->mm == vma->vm_mm) == search_new_forks)
-                               continue;
-
-                       ret = try_to_unmap_one(page, vma,
-                                       rmap_item->address, (void *)flags);
-                       if (ret != SWAP_AGAIN || !page_mapped(page)) {
-                               anon_vma_unlock_read(anon_vma);
-                               goto out;
-                       }
-               }
-               anon_vma_unlock_read(anon_vma);
-       }
-       if (!search_new_forks++)
-               goto again;
-out:
-       return ret;
-}
-
 int rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc)
 {
        struct stable_node *stable_node;
index b3263cb323616febd5a83d13d0ea2595fe2f62f8..c73e0c645d092199fcbafe64048066cce81f2928 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1177,9 +1177,6 @@ out:
 }
 
 /*
- * Subfunctions of try_to_unmap: try_to_unmap_one called
- * repeatedly from try_to_unmap_ksm, try_to_unmap_anon or try_to_unmap_file.
- *
  * @arg: enum ttu_flags will be passed to this argument
  */
 int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
@@ -1521,107 +1518,6 @@ static bool invalid_migration_vma(struct vm_area_struct *vma, void *arg)
        return is_vma_temporary_stack(vma);
 }
 
-/**
- * try_to_unmap_anon - unmap or unlock anonymous page using the object-based
- * rmap method
- * @page: the page to unmap/unlock
- * @flags: action and flags
- *
- * Find all the mappings of a page using the mapping pointer and the vma chains
- * contained in the anon_vma struct it points to.
- *
- * This function is only called from try_to_unmap/try_to_munlock for
- * anonymous pages.
- * When called from try_to_munlock(), the mmap_sem of the mm containing the vma
- * where the page was found will be held for write.  So, we won't recheck
- * vm_flags for that VMA.  That should be OK, because that vma shouldn't be
- * 'LOCKED.
- */
-static int try_to_unmap_anon(struct page *page, enum ttu_flags flags)
-{
-       struct anon_vma *anon_vma;
-       pgoff_t pgoff;
-       struct anon_vma_chain *avc;
-       int ret = SWAP_AGAIN;
-
-       anon_vma = page_lock_anon_vma_read(page);
-       if (!anon_vma)
-               return ret;
-
-       pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
-       anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {
-               struct vm_area_struct *vma = avc->vma;
-               unsigned long address;
-
-               /*
-                * During exec, a temporary VMA is setup and later moved.
-                * The VMA is moved under the anon_vma lock but not the
-                * page tables leading to a race where migration cannot
-                * find the migration ptes. Rather than increasing the
-                * locking requirements of exec(), migration skips
-                * temporary VMAs until after exec() completes.
-                */
-               if (IS_ENABLED(CONFIG_MIGRATION) && (flags & TTU_MIGRATION) &&
-                               is_vma_temporary_stack(vma))
-                       continue;
-
-               address = vma_address(page, vma);
-               ret = try_to_unmap_one(page, vma, address, (void *)flags);
-               if (ret != SWAP_AGAIN || !page_mapped(page))
-                       break;
-       }
-
-       page_unlock_anon_vma_read(anon_vma);
-       return ret;
-}
-
-/**
- * try_to_unmap_file - unmap/unlock file page using the object-based rmap method
- * @page: the page to unmap/unlock
- * @flags: action and flags
- *
- * Find all the mappings of a page using the mapping pointer and the vma chains
- * contained in the address_space struct it points to.
- *
- * This function is only called from try_to_unmap/try_to_munlock for
- * object-based pages.
- * When called from try_to_munlock(), the mmap_sem of the mm containing the vma
- * where the page was found will be held for write.  So, we won't recheck
- * vm_flags for that VMA.  That should be OK, because that vma shouldn't be
- * 'LOCKED.
- */
-static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
-{
-       struct address_space *mapping = page->mapping;
-       pgoff_t pgoff = page->index << compound_order(page);
-       struct vm_area_struct *vma;
-       int ret = SWAP_AGAIN;
-
-       mutex_lock(&mapping->i_mmap_mutex);
-       vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
-               unsigned long address = vma_address(page, vma);
-               ret = try_to_unmap_one(page, vma, address, (void *)flags);
-               if (ret != SWAP_AGAIN || !page_mapped(page))
-                       goto out;
-       }
-
-       if (list_empty(&mapping->i_mmap_nonlinear))
-               goto out;
-
-       /*
-        * We don't bother to try to find the munlocked page in nonlinears.
-        * It's costly. Instead, later, page reclaim logic may call
-        * try_to_unmap(TTU_MUNLOCK) and recover PG_mlocked lazily.
-        */
-       if (TTU_ACTION(flags) == TTU_MUNLOCK)
-               goto out;
-
-       ret = try_to_unmap_nonlinear(page, mapping, vma);
-out:
-       mutex_unlock(&mapping->i_mmap_mutex);
-       return ret;
-}
-
 static int page_not_mapped(struct page *page)
 {
        return !page_mapped(page);
@@ -1689,14 +1585,25 @@ int try_to_unmap(struct page *page, enum ttu_flags flags)
  */
 int try_to_munlock(struct page *page)
 {
+       int ret;
+       struct rmap_walk_control rwc = {
+               .rmap_one = try_to_unmap_one,
+               .arg = (void *)TTU_MUNLOCK,
+               .done = page_not_mapped,
+               /*
+                * We don't bother to try to find the munlocked page in
+                * nonlinears. It's costly. Instead, later, page reclaim logic
+                * may call try_to_unmap() and recover PG_mlocked lazily.
+                */
+               .file_nonlinear = NULL,
+               .anon_lock = page_lock_anon_vma_read,
+
+       };
+
        VM_BUG_ON(!PageLocked(page) || PageLRU(page));
 
-       if (unlikely(PageKsm(page)))
-               return try_to_unmap_ksm(page, TTU_MUNLOCK);
-       else if (PageAnon(page))
-               return try_to_unmap_anon(page, TTU_MUNLOCK);
-       else
-               return try_to_unmap_file(page, TTU_MUNLOCK);
+       ret = rmap_walk(page, &rwc);
+       return ret;
 }
 
 void __put_anon_vma(struct anon_vma *anon_vma)
@@ -1732,8 +1639,18 @@ static struct anon_vma *rmap_walk_anon_lock(struct page *page,
 }
 
 /*
- * 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.
+ * rmap_walk_anon - do something to anonymous page using the object-based
+ * rmap method
+ * @page: the page to be handled
+ * @rwc: control variable according to each walk type
+ *
+ * Find all the mappings of a page using the mapping pointer and the vma chains
+ * contained in the anon_vma struct it points to.
+ *
+ * When called from try_to_munlock(), the mmap_sem of the mm containing the vma
+ * where the page was found will be held for write.  So, we won't recheck
+ * vm_flags for that VMA.  That should be OK, because that vma shouldn't be
+ * LOCKED.
  */
 static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc)
 {
@@ -1763,6 +1680,19 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc)
        return ret;
 }
 
+/*
+ * rmap_walk_file - do something to file page using the object-based rmap method
+ * @page: the page to be handled
+ * @rwc: control variable according to each walk type
+ *
+ * Find all the mappings of a page using the mapping pointer and the vma chains
+ * contained in the address_space struct it points to.
+ *
+ * When called from try_to_munlock(), the mmap_sem of the mm containing the vma
+ * where the page was found will be held for write.  So, we won't recheck
+ * vm_flags for that VMA.  That should be OK, because that vma shouldn't be
+ * LOCKED.
+ */
 static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc)
 {
        struct address_space *mapping = page->mapping;