sparc: add checks for the return value of memblock_alloc*()
[linux-2.6-microblaze.git] / mm / ksm.c
index 6c48ad1..fc64874 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -598,7 +598,7 @@ static struct stable_node *alloc_stable_node_chain(struct stable_node *dup,
                chain->chain_prune_time = jiffies;
                chain->rmap_hlist_len = STABLE_NODE_CHAIN;
 #if defined (CONFIG_DEBUG_VM) && defined(CONFIG_NUMA)
-               chain->nid = -1; /* debug */
+               chain->nid = NUMA_NO_NODE; /* debug */
 #endif
                ksm_stable_node_chains++;
 
@@ -667,6 +667,12 @@ static void remove_node_from_stable_tree(struct stable_node *stable_node)
        free_stable_node(stable_node);
 }
 
+enum get_ksm_page_flags {
+       GET_KSM_PAGE_NOLOCK,
+       GET_KSM_PAGE_LOCK,
+       GET_KSM_PAGE_TRYLOCK
+};
+
 /*
  * get_ksm_page: checks if the page indicated by the stable node
  * is still its ksm page, despite having held no reference to it.
@@ -686,7 +692,8 @@ static void remove_node_from_stable_tree(struct stable_node *stable_node)
  * a page to put something that might look like our key in page->mapping.
  * is on its way to being freed; but it is an anomaly to bear in mind.
  */
-static struct page *get_ksm_page(struct stable_node *stable_node, bool lock_it)
+static struct page *get_ksm_page(struct stable_node *stable_node,
+                                enum get_ksm_page_flags flags)
 {
        struct page *page;
        void *expected_mapping;
@@ -706,8 +713,9 @@ again:
         * case this node is no longer referenced, and should be freed;
         * however, it might mean that the page is under page_ref_freeze().
         * The __remove_mapping() case is easy, again the node is now stale;
-        * but if page is swapcache in migrate_page_move_mapping(), it might
-        * still be our page, in which case it's essential to keep the node.
+        * the same is in reuse_ksm_page() case; but if page is swapcache
+        * in migrate_page_move_mapping(), it might still be our page,
+        * in which case it's essential to keep the node.
         */
        while (!get_page_unless_zero(page)) {
                /*
@@ -728,8 +736,15 @@ again:
                goto stale;
        }
 
-       if (lock_it) {
+       if (flags == GET_KSM_PAGE_TRYLOCK) {
+               if (!trylock_page(page)) {
+                       put_page(page);
+                       return ERR_PTR(-EBUSY);
+               }
+       } else if (flags == GET_KSM_PAGE_LOCK)
                lock_page(page);
+
+       if (flags != GET_KSM_PAGE_NOLOCK) {
                if (READ_ONCE(page->mapping) != expected_mapping) {
                        unlock_page(page);
                        put_page(page);
@@ -763,7 +778,7 @@ static void remove_rmap_item_from_tree(struct rmap_item *rmap_item)
                struct page *page;
 
                stable_node = rmap_item->head;
-               page = get_ksm_page(stable_node, true);
+               page = get_ksm_page(stable_node, GET_KSM_PAGE_LOCK);
                if (!page)
                        goto out;
 
@@ -863,7 +878,7 @@ static int remove_stable_node(struct stable_node *stable_node)
        struct page *page;
        int err;
 
-       page = get_ksm_page(stable_node, true);
+       page = get_ksm_page(stable_node, GET_KSM_PAGE_LOCK);
        if (!page) {
                /*
                 * get_ksm_page did remove_node_from_stable_tree itself.
@@ -1385,7 +1400,7 @@ static struct page *stable_node_dup(struct stable_node **_stable_node_dup,
                 * stable_node parameter itself will be freed from
                 * under us if it returns NULL.
                 */
-               _tree_page = get_ksm_page(dup, false);
+               _tree_page = get_ksm_page(dup, GET_KSM_PAGE_NOLOCK);
                if (!_tree_page)
                        continue;
                nr += 1;
@@ -1508,7 +1523,7 @@ static struct page *__stable_node_chain(struct stable_node **_stable_node_dup,
        if (!is_stable_node_chain(stable_node)) {
                if (is_page_sharing_candidate(stable_node)) {
                        *_stable_node_dup = stable_node;
-                       return get_ksm_page(stable_node, false);
+                       return get_ksm_page(stable_node, GET_KSM_PAGE_NOLOCK);
                }
                /*
                 * _stable_node_dup set to NULL means the stable_node
@@ -1613,7 +1628,8 @@ again:
                         * wrprotected at all times. Any will work
                         * fine to continue the walk.
                         */
-                       tree_page = get_ksm_page(stable_node_any, false);
+                       tree_page = get_ksm_page(stable_node_any,
+                                                GET_KSM_PAGE_NOLOCK);
                }
                VM_BUG_ON(!stable_node_dup ^ !!stable_node_any);
                if (!tree_page) {
@@ -1673,7 +1689,12 @@ again:
                         * It would be more elegant to return stable_node
                         * than kpage, but that involves more changes.
                         */
-                       tree_page = get_ksm_page(stable_node_dup, true);
+                       tree_page = get_ksm_page(stable_node_dup,
+                                                GET_KSM_PAGE_TRYLOCK);
+
+                       if (PTR_ERR(tree_page) == -EBUSY)
+                               return ERR_PTR(-EBUSY);
+
                        if (unlikely(!tree_page))
                                /*
                                 * The tree may have been rebalanced,
@@ -1842,7 +1863,8 @@ again:
                         * wrprotected at all times. Any will work
                         * fine to continue the walk.
                         */
-                       tree_page = get_ksm_page(stable_node_any, false);
+                       tree_page = get_ksm_page(stable_node_any,
+                                                GET_KSM_PAGE_NOLOCK);
                }
                VM_BUG_ON(!stable_node_dup ^ !!stable_node_any);
                if (!tree_page) {
@@ -2068,6 +2090,9 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item)
        remove_rmap_item_from_tree(rmap_item);
 
        if (kpage) {
+               if (PTR_ERR(kpage) == -EBUSY)
+                       return;
+
                err = try_to_merge_with_ksm_page(rmap_item, page, kpage);
                if (!err) {
                        /*
@@ -2242,7 +2267,8 @@ static struct rmap_item *scan_get_next_rmap_item(struct page **page)
 
                        list_for_each_entry_safe(stable_node, next,
                                                 &migrate_nodes, list) {
-                               page = get_ksm_page(stable_node, false);
+                               page = get_ksm_page(stable_node,
+                                                   GET_KSM_PAGE_NOLOCK);
                                if (page)
                                        put_page(page);
                                cond_resched();
@@ -2642,6 +2668,31 @@ again:
                goto again;
 }
 
+bool reuse_ksm_page(struct page *page,
+                   struct vm_area_struct *vma,
+                   unsigned long address)
+{
+#ifdef CONFIG_DEBUG_VM
+       if (WARN_ON(is_zero_pfn(page_to_pfn(page))) ||
+                       WARN_ON(!page_mapped(page)) ||
+                       WARN_ON(!PageLocked(page))) {
+               dump_page(page, "reuse_ksm_page");
+               return false;
+       }
+#endif
+
+       if (PageSwapCache(page) || !page_stable_node(page))
+               return false;
+       /* Prohibit parallel get_ksm_page() */
+       if (!page_ref_freeze(page, 1))
+               return false;
+
+       page_move_anon_rmap(page, vma);
+       page->index = linear_page_index(vma, address);
+       page_ref_unfreeze(page, 1);
+
+       return true;
+}
 #ifdef CONFIG_MIGRATION
 void ksm_migrate_page(struct page *newpage, struct page *oldpage)
 {