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.

Signed-off-by: Tim Chen <tim.c.c...@linux.intel.com>
Signed-off-by: "Huang, Ying" <ying.hu...@intel.com>
---
 include/linux/swap.h |  6 ++++++
 mm/swap_state.c      |  4 ++++
 mm/swapfile.c        | 47 +++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/include/linux/swap.h b/include/linux/swap.h
index 6bda950..13bbc5f 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -424,6 +424,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 *);
@@ -518,6 +519,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;
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 0e377f5..1f52ff6 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -314,6 +314,10 @@ struct page *__read_swap_cache_async(swp_entry_t entry, 
gfp_t gfp_mask,
        *new_page_allocated = false;
 
        do {
+               /* Just skip read ahead for unused swap slot */
+               if (!__swp_swapcount(entry))
+                       return NULL;
+
                /*
                 * First check the swap cache.  Since this is normally
                 * called after lookup_swap_cache() failed, re-calling
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 4f1b721..19e3ea9 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -803,7 +803,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;
@@ -819,13 +819,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;
@@ -838,6 +833,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;
@@ -993,6 +1006,28 @@ int page_swapcount(struct page *page)
 
 /*
  * 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.
  */
 int swp_swapcount(swp_entry_t entry)
-- 
2.5.5

Reply via email to