diff options
-rw-r--r-- | include/linux/swap.h | 6 | ||||
-rw-r--r-- | mm/swap_state.c | 4 | ||||
-rw-r--r-- | mm/swapfile.c | 47 |
3 files changed, 51 insertions, 6 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h index 648a32b58e3e..3116382067cd 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -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; diff --git a/mm/swap_state.c b/mm/swap_state.c index 3863acd6189c..3d76d80c07d6 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -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. */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 66e95eb73040..7e888de35c41 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -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; @@ -988,6 +1001,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) |