Commit:     9ae9d68cbf3fe0ec17c17c9ecaa2188ffb854a66
Parent:     5b94f675f57e4ff16c8fda09088d7480a84dcd91
Author:     Fengguang Wu <[EMAIL PROTECTED]>
AuthorDate: Tue May 8 08:44:36 2007 +0200
Committer:  Jens Axboe <[EMAIL PROTECTED]>
CommitDate: Tue May 8 08:44:36 2007 +0200

    [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
            if (!loff || nr_pages > 1)
                    page_cache_readahead(mapping, &in->f_ra, in, index, 
    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 
      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 <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Jens Axboe <[EMAIL PROTECTED]>
 fs/splice.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/splice.c b/fs/splice.c
index 5428b0f..2282650 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -378,10 +378,11 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                         * If in nonblock mode then dont block on waiting
                         * for an in-flight io page
-                       if (flags & SPLICE_F_NONBLOCK)
-                               break;
-                       lock_page(page);
+                       if (flags & SPLICE_F_NONBLOCK) {
+                               if (TestSetPageLocked(page))
+                                       break;
+                       } else
+                               lock_page(page);
                         * page was truncated, stop here. if this isn't the
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at

Reply via email to