mm/swap: skip readahead for unreferenced swap slots
authorTim Chen <tim.c.chen@linux.intel.com>
Wed, 22 Feb 2017 23:45:29 +0000 (15:45 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Feb 2017 00:41:30 +0000 (16:41 -0800)
We can avoid needlessly allocating page for swap slots that are not used
by anyone.  No pages have to be read in for these slots.

Link: http://lkml.kernel.org/r/0784b3f20b9bd3aa5552219624cb78dc4ae710c9.1484082593.git.tim.c.chen@linux.intel.com
Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
Cc: Aaron Lu <aaron.lu@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net> escreveu:
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Shaohua Li <shli@kernel.org>
Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
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/swapfile.c

index 648a32b58e3eff7d26af5ae2dd3b0487ad5c0782..3116382067cd8b8bd2f754c62d2276d3c943a415 100644 (file)
@@ -398,6 +398,7 @@ extern unsigned int count_swap_pages(int, int);
 extern sector_t map_swap_page(struct page *, struct block_device **);
 extern sector_t swapdev_block(int, pgoff_t);
 extern int page_swapcount(struct page *);
+extern int __swp_swapcount(swp_entry_t entry);
 extern int swp_swapcount(swp_entry_t entry);
 extern struct swap_info_struct *page_swap_info(struct page *);
 extern bool reuse_swap_page(struct page *, int *);
@@ -492,6 +493,11 @@ static inline int page_swapcount(struct page *page)
        return 0;
 }
 
+static inline int __swp_swapcount(swp_entry_t entry)
+{
+       return 0;
+}
+
 static inline int swp_swapcount(swp_entry_t entry)
 {
        return 0;
index 3863acd6189cba35cb0d2a811169b6b69f37981f..3d76d80c07d6d61c3feb3b8a959e34c70f862a80 100644 (file)
@@ -323,6 +323,10 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                if (found_page)
                        break;
 
+               /* Just skip read ahead for unused swap slot */
+               if (!__swp_swapcount(entry))
+                       return NULL;
+
                /*
                 * Get a new page to read into from swap.
                 */
index 66e95eb730407ec02604262de296278aab7b5880..7e888de35c41a62ade94ef7401d0c07b47943a32 100644 (file)
@@ -798,7 +798,7 @@ swp_entry_t get_swap_page_of_type(int type)
        return (swp_entry_t) {0};
 }
 
-static struct swap_info_struct *_swap_info_get(swp_entry_t entry)
+static struct swap_info_struct *__swap_info_get(swp_entry_t entry)
 {
        struct swap_info_struct *p;
        unsigned long offset, type;
@@ -814,13 +814,8 @@ static struct swap_info_struct *_swap_info_get(swp_entry_t entry)
        offset = swp_offset(entry);
        if (offset >= p->max)
                goto bad_offset;
-       if (!p->swap_map[offset])
-               goto bad_free;
        return p;
 
-bad_free:
-       pr_err("swap_info_get: %s%08lx\n", Unused_offset, entry.val);
-       goto out;
 bad_offset:
        pr_err("swap_info_get: %s%08lx\n", Bad_offset, entry.val);
        goto out;
@@ -833,6 +828,24 @@ out:
        return NULL;
 }
 
+static struct swap_info_struct *_swap_info_get(swp_entry_t entry)
+{
+       struct swap_info_struct *p;
+
+       p = __swap_info_get(entry);
+       if (!p)
+               goto out;
+       if (!p->swap_map[swp_offset(entry)])
+               goto bad_free;
+       return p;
+
+bad_free:
+       pr_err("swap_info_get: %s%08lx\n", Unused_offset, entry.val);
+       goto out;
+out:
+       return NULL;
+}
+
 static struct swap_info_struct *swap_info_get(swp_entry_t entry)
 {
        struct swap_info_struct *p;
@@ -986,6 +999,28 @@ int page_swapcount(struct page *page)
        return count;
 }
 
+/*
+ * How many references to @entry are currently swapped out?
+ * This does not give an exact answer when swap count is continued,
+ * but does include the high COUNT_CONTINUED flag to allow for that.
+ */
+int __swp_swapcount(swp_entry_t entry)
+{
+       int count = 0;
+       pgoff_t offset;
+       struct swap_info_struct *si;
+       struct swap_cluster_info *ci;
+
+       si = __swap_info_get(entry);
+       if (si) {
+               offset = swp_offset(entry);
+               ci = lock_cluster_or_swap_info(si, offset);
+               count = swap_count(si->swap_map[offset]);
+               unlock_cluster_or_swap_info(si, ci);
+       }
+       return count;
+}
+
 /*
  * How many references to @entry are currently swapped out?
  * This considers COUNT_CONTINUED so it returns exact answer.