mm, THP, swap: move anonymous THP split logic to vmscan
authorMinchan Kim <minchan@kernel.org>
Thu, 6 Jul 2017 22:37:24 +0000 (15:37 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 6 Jul 2017 23:24:31 +0000 (16:24 -0700)
The add_to_swap aims to allocate swap_space(ie, swap slot and swapcache)
so if it fails due to lack of space in case of THP or something(hdd swap
but tries THP swapout) *caller* rather than add_to_swap itself should
split the THP page and retry it with base page which is more natural.

Link: http://lkml.kernel.org/r/20170515112522.32457-4-ying.huang@intel.com
Signed-off-by: Minchan Kim <minchan@kernel.org>
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Ebru Akagunduz <ebru.akagunduz@gmail.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Shaohua Li <shli@kernel.org>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/swap.h
mm/swap_state.c
mm/vmscan.c

index ead6fd7966b4fe1a25f5dc9112cdc5442576e55f..5ab1c98c7d274f22eeed7a58c298068fbf861477 100644 (file)
@@ -353,7 +353,7 @@ extern struct address_space *swapper_spaces[];
                >> SWAP_ADDRESS_SPACE_SHIFT])
 extern unsigned long total_swapcache_pages(void);
 extern void show_swap_cache_info(void);
-extern int add_to_swap(struct page *, struct list_head *list);
+extern int add_to_swap(struct page *page);
 extern int add_to_swap_cache(struct page *, swp_entry_t, gfp_t);
 extern int __add_to_swap_cache(struct page *page, swp_entry_t entry);
 extern void __delete_from_swap_cache(struct page *);
@@ -473,7 +473,7 @@ static inline struct page *lookup_swap_cache(swp_entry_t swp)
        return NULL;
 }
 
-static inline int add_to_swap(struct page *page, struct list_head *list)
+static inline int add_to_swap(struct page *page)
 {
        return 0;
 }
index 0ad214d7a7ad22c1ee871759f07d70e6f74be0c8..9c71b6b2562fee671e710347c7f4ff6ae54400ac 100644 (file)
@@ -184,7 +184,7 @@ void __delete_from_swap_cache(struct page *page)
  * Allocate swap space for the page and add the page to the
  * swap cache.  Caller needs to hold the page lock. 
  */
-int add_to_swap(struct page *page, struct list_head *list)
+int add_to_swap(struct page *page)
 {
        swp_entry_t entry;
        int err;
@@ -192,12 +192,12 @@ int add_to_swap(struct page *page, struct list_head *list)
        VM_BUG_ON_PAGE(!PageLocked(page), page);
        VM_BUG_ON_PAGE(!PageUptodate(page), page);
 
-retry:
        entry = get_swap_page(page);
        if (!entry.val)
-               goto fail;
+               return 0;
+
        if (mem_cgroup_try_charge_swap(page, entry))
-               goto fail_free;
+               goto fail;
 
        /*
         * Radix-tree node allocations from PF_MEMALLOC contexts could
@@ -218,23 +218,12 @@ retry:
                 * add_to_swap_cache() doesn't return -EEXIST, so we can safely
                 * clear SWAP_HAS_CACHE flag.
                 */
-               goto fail_free;
-
-       if (PageTransHuge(page)) {
-               err = split_huge_page_to_list(page, list);
-               if (err) {
-                       delete_from_swap_cache(page);
-                       return 0;
-               }
-       }
+               goto fail;
 
        return 1;
 
-fail_free:
-       put_swap_page(page, entry);
 fail:
-       if (PageTransHuge(page) && !split_huge_page_to_list(page, list))
-               goto retry;
+       put_swap_page(page, entry);
        return 0;
 }
 
index cb7c154a4a9dc10f4ab7399908f34817e3389757..729e37f02de67a171f579add5263c23340825886 100644 (file)
@@ -1125,8 +1125,23 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                    !PageSwapCache(page)) {
                        if (!(sc->gfp_mask & __GFP_IO))
                                goto keep_locked;
-                       if (!add_to_swap(page, page_list))
+                       if (!add_to_swap(page)) {
+                               if (!PageTransHuge(page))
+                                       goto activate_locked;
+                               /* Split THP and swap individual base pages */
+                               if (split_huge_page_to_list(page, page_list))
+                                       goto activate_locked;
+                               if (!add_to_swap(page))
+                                       goto activate_locked;
+                       }
+
+                       /* XXX: We don't support THP writes */
+                       if (PageTransHuge(page) &&
+                                 split_huge_page_to_list(page, page_list)) {
+                               delete_from_swap_cache(page);
                                goto activate_locked;
+                       }
+
                        may_enter_fs = 1;
 
                        /* Adding to swap updated mapping */