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>
This commit is contained in:
committed by
Linus Torvalds
parent
5402b976ae
commit
8952898b0d
@ -1769,31 +1769,48 @@ get_swap_info_struct(unsigned type)
|
|||||||
*/
|
*/
|
||||||
int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
|
int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
|
||||||
{
|
{
|
||||||
|
struct swap_info_struct *si;
|
||||||
int our_page_cluster = page_cluster;
|
int our_page_cluster = page_cluster;
|
||||||
int ret = 0, i = 1 << our_page_cluster;
|
pgoff_t target, toff;
|
||||||
unsigned long toff;
|
pgoff_t base, end;
|
||||||
struct swap_info_struct *swapdev = swp_type(entry) + swap_info;
|
int nr_pages = 0;
|
||||||
|
|
||||||
if (!our_page_cluster) /* no readahead */
|
if (!our_page_cluster) /* no readahead */
|
||||||
return 0;
|
return 0;
|
||||||
toff = (swp_offset(entry) >> our_page_cluster) << our_page_cluster;
|
|
||||||
if (!toff) /* first page is swap header */
|
si = &swap_info[swp_type(entry)];
|
||||||
toff++, i--;
|
target = swp_offset(entry);
|
||||||
*offset = toff;
|
base = (target >> our_page_cluster) << our_page_cluster;
|
||||||
|
end = base + (1 << our_page_cluster);
|
||||||
|
if (!base) /* first page is swap header */
|
||||||
|
base++;
|
||||||
|
|
||||||
spin_lock(&swap_lock);
|
spin_lock(&swap_lock);
|
||||||
do {
|
if (end > si->max) /* don't go beyond end of map */
|
||||||
/* Don't read-ahead past the end of the swap area */
|
end = si->max;
|
||||||
if (toff >= swapdev->max)
|
|
||||||
break;
|
/* Count contiguous allocated slots above our target */
|
||||||
|
for (toff = target; ++toff < end; nr_pages++) {
|
||||||
/* Don't read in free or bad pages */
|
/* Don't read in free or bad pages */
|
||||||
if (!swapdev->swap_map[toff])
|
if (!si->swap_map[toff])
|
||||||
break;
|
break;
|
||||||
if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
|
if (si->swap_map[toff] == SWAP_MAP_BAD)
|
||||||
break;
|
break;
|
||||||
toff++;
|
}
|
||||||
ret++;
|
/* Count contiguous allocated slots below our target */
|
||||||
} while (--i);
|
for (toff = target; --toff >= base; nr_pages++) {
|
||||||
|
/* Don't read in free or bad pages */
|
||||||
|
if (!si->swap_map[toff])
|
||||||
|
break;
|
||||||
|
if (si->swap_map[toff] == SWAP_MAP_BAD)
|
||||||
|
break;
|
||||||
|
}
|
||||||
spin_unlock(&swap_lock);
|
spin_unlock(&swap_lock);
|
||||||
return ret;
|
|
||||||
|
/*
|
||||||
|
* Indicate starting offset, and return number of pages to get:
|
||||||
|
* if only 1, say 0, since there's then no readahead to be done.
|
||||||
|
*/
|
||||||
|
*offset = ++toff;
|
||||||
|
return nr_pages? ++nr_pages: 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user