aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFengguang Wu <fengguang.wu@gmail.com>2007-05-08 02:44:36 -0400
committerJens Axboe <jens.axboe@oracle.com>2007-05-08 02:44:36 -0400
commit9ae9d68cbf3fe0ec17c17c9ecaa2188ffb854a66 (patch)
treed29b5e56b7c18c06a1a08d6e27c8862205fa2d86
parent5b94f675f57e4ff16c8fda09088d7480a84dcd91 (diff)
[PATCH] splice(): fix interaction with readahead
Eric Dumazet, thank you for disclosing this bug. Readahead logic somehow fails to populate the page range with data. It can be because 1) the readahead routine is not always called in the following lines of fs/splice.c: if (!loff || nr_pages > 1) page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages); 2) even called, page_cache_readahead() wont guarantee the pages are there. It wont submit readahead I/O for pages already in the radix tree, or when (ra_pages == 0), or after 256 cache hits. In your case, it should be because of the retried reads, which lead to excessive cache hits, and disables readahead at some time. And that _one_ failure of readahead blocks the whole read process. The application receives EAGAIN and retries the read, but __generic_file_splice_read() refuse to make progress: - in the previous invocation, it has allocated a blank page and inserted it into the radix tree, but never has the chance to start I/O for it: the test of SPLICE_F_NONBLOCK goes before that. - in the retried invocation, the readahead code will neither get out of the cache hit mode, nor will it submit I/O for an already existing page. Cc: Eric Dumazet <dada1@cosmosbay.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--fs/splice.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/fs/splice.c b/fs/splice.c
index 5428b0ff3b6f..2282650bdbe8 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -378,10 +378,11 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
378 * If in nonblock mode then dont block on waiting 378 * If in nonblock mode then dont block on waiting
379 * for an in-flight io page 379 * for an in-flight io page
380 */ 380 */
381 if (flags & SPLICE_F_NONBLOCK) 381 if (flags & SPLICE_F_NONBLOCK) {
382 break; 382 if (TestSetPageLocked(page))
383 383 break;
384 lock_page(page); 384 } else
385 lock_page(page);
385 386
386 /* 387 /*
387 * page was truncated, stop here. if this isn't the 388 * page was truncated, stop here. if this isn't the