OSDN Git Service

cifs: fail i/o on soft mounts if sessionsetup errors out
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / mm / ksm.c
index b5cd647..f516130 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -283,7 +283,8 @@ static inline struct rmap_item *alloc_rmap_item(void)
 {
        struct rmap_item *rmap_item;
 
-       rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL);
+       rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL |
+                                               __GFP_NORETRY | __GFP_NOWARN);
        if (rmap_item)
                ksm_rmap_items++;
        return rmap_item;
@@ -713,13 +714,13 @@ static int remove_stable_node(struct stable_node *stable_node)
                return 0;
        }
 
-       if (WARN_ON_ONCE(page_mapped(page))) {
-               /*
-                * This should not happen: but if it does, just refuse to let
-                * merge_across_nodes be switched - there is no need to panic.
-                */
-               err = -EBUSY;
-       } else {
+       /*
+        * Page could be still mapped if this races with __mmput() running in
+        * between ksm_exit() and exit_mmap(). Just refuse to let
+        * merge_across_nodes/max_page_sharing be switched.
+        */
+       err = -EBUSY;
+       if (!page_mapped(page)) {
                /*
                 * The stable node did not yet appear stale to get_ksm_page(),
                 * since that allows for an unmapped ksm page to be recognized
@@ -1493,8 +1494,22 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item)
        tree_rmap_item =
                unstable_tree_search_insert(rmap_item, page, &tree_page);
        if (tree_rmap_item) {
+               bool split;
+
                kpage = try_to_merge_two_pages(rmap_item, page,
                                                tree_rmap_item, tree_page);
+               /*
+                * If both pages we tried to merge belong to the same compound
+                * page, then we actually ended up increasing the reference
+                * count of the same compound page twice, and split_huge_page
+                * failed.
+                * Here we set a flag if that happened, and we use it later to
+                * try split_huge_page again. Since we call put_page right
+                * afterwards, the reference count will be correct and
+                * split_huge_page should succeed.
+                */
+               split = PageTransCompound(page)
+                       && compound_head(page) == compound_head(tree_page);
                put_page(tree_page);
                if (kpage) {
                        /*
@@ -1519,6 +1534,20 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item)
                                break_cow(tree_rmap_item);
                                break_cow(rmap_item);
                        }
+               } else if (split) {
+                       /*
+                        * We are here if we tried to merge two pages and
+                        * failed because they both belonged to the same
+                        * compound page. We will split the page now, but no
+                        * merging will take place.
+                        * We do not want to add the cost of a full lock; if
+                        * the page is locked, it is better to skip it and
+                        * perhaps try again later.
+                        */
+                       if (!trylock_page(page))
+                               return;
+                       split_huge_page(page);
+                       unlock_page(page);
                }
        }
 }