diff options
author | Hugh Dickins <hugh@veritas.com> | 2008-02-05 01:28:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:15 -0500 |
commit | 8952898b0d25223f38daf46b86156fd1c4d17ad0 (patch) | |
tree | 10912460cd9d42195d4aba8250ed1c3bd3577bb4 /mm | |
parent | 5402b976ae0be96b3a32f3508ab7308c380d6477 (diff) |
swapin: fix valid_swaphandles defect
valid_swaphandles is supposed to do a quick pass over the swap map entries
neigbouring the entry which swapin_readahead is targetting, to determine for
it a range worth reading all together. But since it always starts its search
from the beginning of the swap "cluster", a reject (free entry) there
immediately curtails the readaround, and every swapin_readahead from that
cluster is for just a single page. Instead scan forwards and backwards around
the target entry.
Use better names for some variables: a swap_info pointer is usually called
"si" not "swapdev". And at the end, if only the target page should be read,
return count of 0 to disable readaround, to avoid the unnecessarily repeated
call to read_swap_cache_async.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Acked-by: Rik van Riel <riel@surriel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/swapfile.c | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index ab93505dfbf4..f5ba723faf81 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -1769,31 +1769,48 @@ get_swap_info_struct(unsigned type) | |||
1769 | */ | 1769 | */ |
1770 | int valid_swaphandles(swp_entry_t entry, unsigned long *offset) | 1770 | int valid_swaphandles(swp_entry_t entry, unsigned long *offset) |
1771 | { | 1771 | { |
1772 | struct swap_info_struct *si; | ||
1772 | int our_page_cluster = page_cluster; | 1773 | int our_page_cluster = page_cluster; |
1773 | int ret = 0, i = 1 << our_page_cluster; | 1774 | pgoff_t target, toff; |
1774 | unsigned long toff; | 1775 | pgoff_t base, end; |
1775 | struct swap_info_struct *swapdev = swp_type(entry) + swap_info; | 1776 | int nr_pages = 0; |
1776 | 1777 | ||
1777 | if (!our_page_cluster) /* no readahead */ | 1778 | if (!our_page_cluster) /* no readahead */ |
1778 | return 0; | 1779 | return 0; |
1779 | toff = (swp_offset(entry) >> our_page_cluster) << our_page_cluster; | 1780 | |
1780 | if (!toff) /* first page is swap header */ | 1781 | si = &swap_info[swp_type(entry)]; |
1781 | toff++, i--; | 1782 | target = swp_offset(entry); |
1782 | *offset = toff; | 1783 | base = (target >> our_page_cluster) << our_page_cluster; |
1784 | end = base + (1 << our_page_cluster); | ||
1785 | if (!base) /* first page is swap header */ | ||
1786 | base++; | ||
1783 | 1787 | ||
1784 | spin_lock(&swap_lock); | 1788 | spin_lock(&swap_lock); |
1785 | do { | 1789 | if (end > si->max) /* don't go beyond end of map */ |
1786 | /* Don't read-ahead past the end of the swap area */ | 1790 | end = si->max; |
1787 | if (toff >= swapdev->max) | 1791 | |
1792 | /* Count contiguous allocated slots above our target */ | ||
1793 | for (toff = target; ++toff < end; nr_pages++) { | ||
1794 | /* Don't read in free or bad pages */ | ||
1795 | if (!si->swap_map[toff]) | ||
1796 | break; | ||
1797 | if (si->swap_map[toff] == SWAP_MAP_BAD) | ||
1788 | break; | 1798 | break; |
1799 | } | ||
1800 | /* Count contiguous allocated slots below our target */ | ||
1801 | for (toff = target; --toff >= base; nr_pages++) { | ||
1789 | /* Don't read in free or bad pages */ | 1802 | /* Don't read in free or bad pages */ |
1790 | if (!swapdev->swap_map[toff]) | 1803 | if (!si->swap_map[toff]) |
1791 | break; | 1804 | break; |
1792 | if (swapdev->swap_map[toff] == SWAP_MAP_BAD) | 1805 | if (si->swap_map[toff] == SWAP_MAP_BAD) |
1793 | break; | 1806 | break; |
1794 | toff++; | 1807 | } |
1795 | ret++; | ||
1796 | } while (--i); | ||
1797 | spin_unlock(&swap_lock); | 1808 | spin_unlock(&swap_lock); |
1798 | return ret; | 1809 | |
1810 | /* | ||
1811 | * Indicate starting offset, and return number of pages to get: | ||
1812 | * if only 1, say 0, since there's then no readahead to be done. | ||
1813 | */ | ||
1814 | *offset = ++toff; | ||
1815 | return nr_pages? ++nr_pages: 0; | ||
1799 | } | 1816 | } |