Commit 6b10c6c9 authored by Fengguang Wu's avatar Fengguang Wu Committed by Linus Torvalds

readahead: basic support of interleaved reads

This is a simplified version of the pagecache context based readahead.  It
handles the case of multiple threads reading on the same fd and invalidating
each others' readahead state.  It does the trick by scanning the pagecache and
recovering the current read stream's readahead status.

The algorithm works in a opportunistic way, in that it does not try to detect
interleaved reads _actively_, which requires a probe into the page cache
(which means a little more overhead for random reads).  It only tries to
handle a previously started sequential readahead whose state was overwritten
by another concurrent stream, and it can do this job pretty well.

Negative and positive examples(or what you can expect from it):

1) it cannot detect and serve perfect request-by-request interleaved reads
   right:
	time	stream 1  stream 2
	0 	1
	1 	          1001
	2 	2
	3 	          1002
	4 	3
	5 	          1003
	6 	4
	7 	          1004
	8 	5
	9	          1005

Here no single readahead will be carried out.

2) However, if it's two concurrent reads by two threads, the chance of the
   initial sequential readahead be started is huge. Once the first sequential
   readahead is started for a stream, this patch will ensure that the readahead
   window continues to rampup and won't be disturbed by other streams.

	time	stream 1  stream 2
	0 	1
	1 	2
	2 	          1001
	3 	3
	4 	          1002
	5 	          1003
	6 	4
	7 	5
	8 	          1004
	9 	6
	10	          1005
	11	7
	12	          1006
	13	          1007

Here stream 1 will start a readahead at page 2, and stream 2 will start its
first readahead at page 1003.  From then on the two streams will be served
right.

Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarFengguang Wu <wfg@mail.ustc.edu.cn>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6df8ba4f
...@@ -379,6 +379,29 @@ ondemand_readahead(struct address_space *mapping, ...@@ -379,6 +379,29 @@ ondemand_readahead(struct address_space *mapping,
offset, req_size, 0); offset, req_size, 0);
} }
/*
* Hit a marked page without valid readahead state.
* E.g. interleaved reads.
* Query the pagecache for async_size, which normally equals to
* readahead size. Ramp it up and use it as the new readahead size.
*/
if (hit_readahead_marker) {
pgoff_t start;
read_lock_irq(&mapping->tree_lock);
start = radix_tree_next_hole(&mapping->page_tree, offset, max+1);
read_unlock_irq(&mapping->tree_lock);
if (!start || start - offset > max)
return 0;
ra->start = start;
ra->size = start - offset; /* old async_size */
ra->size = get_next_ra_size(ra, max);
ra->async_size = ra->size;
goto readit;
}
/* /*
* It may be one of * It may be one of
* - first read on start of file * - first read on start of file
...@@ -390,16 +413,6 @@ ondemand_readahead(struct address_space *mapping, ...@@ -390,16 +413,6 @@ ondemand_readahead(struct address_space *mapping,
ra->size = get_init_ra_size(req_size, max); ra->size = get_init_ra_size(req_size, max);
ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size; ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size;
/*
* Hit on a marked page without valid readahead state.
* E.g. interleaved reads.
* Not knowing its readahead pos/size, bet on the minimal possible one.
*/
if (hit_readahead_marker) {
ra->start++;
ra->size = get_next_ra_size(ra, max);
}
readit: readit:
return ra_submit(ra, mapping, filp); return ra_submit(ra, mapping, filp);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment