aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2008-02-05 01:28:45 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:15 -0500
commit8952898b0d25223f38daf46b86156fd1c4d17ad0 (patch)
tree10912460cd9d42195d4aba8250ed1c3bd3577bb4
parent5402b976ae0be96b3a32f3508ab7308c380d6477 (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>
-rw-r--r--mm/swapfile.c49
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 */
1770int valid_swaphandles(swp_entry_t entry, unsigned long *offset) 1770int 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}