From c203378d085dd1587e39a8b2bfa840c8bca55261 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 16 Jun 2009 15:31:36 -0700 Subject: [PATCH] --- yaml --- r: 151514 b: refs/heads/master c: 10be0b372cac50e2e7a477852f98bf069a97a3fa h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/mm/readahead.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index ba8db056178e..8fdf40b26347 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 045a2529a3513faed2d45bd82f9013b124309d94 +refs/heads/master: 10be0b372cac50e2e7a477852f98bf069a97a3fa diff --git a/trunk/mm/readahead.c b/trunk/mm/readahead.c index ceed7e4790bd..aa1aa2345235 100644 --- a/trunk/mm/readahead.c +++ b/trunk/mm/readahead.c @@ -329,6 +329,59 @@ static unsigned long get_next_ra_size(struct file_ra_state *ra, * it approaches max_readhead. */ +/* + * Count contiguously cached pages from @offset-1 to @offset-@max, + * this count is a conservative estimation of + * - length of the sequential read sequence, or + * - thrashing threshold in memory tight systems + */ +static pgoff_t count_history_pages(struct address_space *mapping, + struct file_ra_state *ra, + pgoff_t offset, unsigned long max) +{ + pgoff_t head; + + rcu_read_lock(); + head = radix_tree_prev_hole(&mapping->page_tree, offset - 1, max); + rcu_read_unlock(); + + return offset - 1 - head; +} + +/* + * page cache context based read-ahead + */ +static int try_context_readahead(struct address_space *mapping, + struct file_ra_state *ra, + pgoff_t offset, + unsigned long req_size, + unsigned long max) +{ + pgoff_t size; + + size = count_history_pages(mapping, ra, offset, max); + + /* + * no history pages: + * it could be a random read + */ + if (!size) + return 0; + + /* + * starts from beginning of file: + * it is a strong indication of long-run stream (or whole-file-read) + */ + if (size >= offset) + size *= 2; + + ra->start = offset; + ra->size = get_init_ra_size(size + req_size, max); + ra->async_size = ra->size; + + return 1; +} + /* * A minimal readahead algorithm for trivial sequential/random reads. */ @@ -394,6 +447,13 @@ ondemand_readahead(struct address_space *mapping, if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL) goto initial_readahead; + /* + * Query the page cache and look for the traces(cached history pages) + * that a sequential stream would leave behind. + */ + if (try_context_readahead(mapping, ra, offset, req_size, max)) + goto readit; + /* * standalone, small random read * Read as is, and do not pollute the readahead state.