]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - mm/ksm.c
ksm: rmap_walk to remove_migation_ptes
[net-next-2.6.git] / mm / ksm.c
index 20f46a7b2799aaca1366348a3929897c32a0c27c..dfdc292d3626d43ab638871e103dcba9899d29b5 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1656,6 +1656,71 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_MIGRATION
+int rmap_walk_ksm(struct page *page, int (*rmap_one)(struct page *,
+                 struct vm_area_struct *, unsigned long, void *), void *arg)
+{
+       struct stable_node *stable_node;
+       struct hlist_node *hlist;
+       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 ret;
+again:
+       hlist_for_each_entry(rmap_item, hlist, &stable_node->hlist, hlist) {
+               struct anon_vma *anon_vma = rmap_item->anon_vma;
+               struct vm_area_struct *vma;
+
+               spin_lock(&anon_vma->lock);
+               list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
+                       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 = rmap_one(page, vma, rmap_item->address, arg);
+                       if (ret != SWAP_AGAIN) {
+                               spin_unlock(&anon_vma->lock);
+                               goto out;
+                       }
+               }
+               spin_unlock(&anon_vma->lock);
+       }
+       if (!search_new_forks++)
+               goto again;
+out:
+       return ret;
+}
+
+void ksm_migrate_page(struct page *newpage, struct page *oldpage)
+{
+       struct stable_node *stable_node;
+
+       VM_BUG_ON(!PageLocked(oldpage));
+       VM_BUG_ON(!PageLocked(newpage));
+       VM_BUG_ON(newpage->mapping != oldpage->mapping);
+
+       stable_node = page_stable_node(newpage);
+       if (stable_node) {
+               VM_BUG_ON(stable_node->page != oldpage);
+               stable_node->page = newpage;
+       }
+}
+#endif /* CONFIG_MIGRATION */
+
 #ifdef CONFIG_SYSFS
 /*
  * This all compiles without CONFIG_SYSFS, but is a waste of space.