From 9ae9d68cbf3fe0ec17c17c9ecaa2188ffb854a66 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Tue, 8 May 2007 08:44:36 +0200 Subject: [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 Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- fs/splice.c | 9 +++++---- 1 file 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 -- cgit v1.1 From 86aa5ac53e478c94ee39a15b6eadde1ed1317be3 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 8 May 2007 08:46:19 +0200 Subject: [PATCH] splice: always call into page_cache_readahead() Don't try to guess what the read-ahead logic will do, allow it to make its own decisions. Signed-off-by: Jens Axboe --- fs/splice.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 2282650..12f2828 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -289,12 +289,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, nr_pages = PIPE_BUFFERS; /* - * Initiate read-ahead on this page range. however, don't call into - * read-ahead if this is a non-zero offset (we are likely doing small - * chunk splice and the page is already there) for a single page. + * Don't try to 2nd guess the read-ahead logic, call into + * page_cache_readahead() like the page cache reads would do. */ - if (!loff || nr_pages > 1) - page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages); + page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages); /* * Now fill in the holes: -- cgit v1.1 From 821de3a27bf33f11ec878562577c586cd5f83c64 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 8 May 2007 19:12:23 +0200 Subject: [PATCH] ll_rw_blk: fix missing bounce in blk_rq_map_kern() I think we might just need the blk_map_kern users now. For the async execute I added the bounce code already and the block SG_IO has it atleady. I think the blk_map_kern bounce code got dropped because we thought the correct gfp_t would be passed in. But I think all we need is the patch below and all the paths are take care of. The patch is not tested. Patch was made against scsi-misc. The last place that is sending non sg commands may just be md/dm-emc.c but that is is just waiting on alasdair to take some patches that fix that and a bunch of junk in there including adding bounce support. If the patch below is ok though and dm-emc finally gets converted then it will have sg and bonce buffer support. Signed-off-by: Mike Christie Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 5873861..d99d402 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2558,6 +2558,7 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, bio->bi_rw |= (1 << BIO_RW); blk_rq_bio_prep(q, rq, bio); + blk_queue_bounce(q, &rq->bio); rq->buffer = rq->data = NULL; return 0; } -- cgit v1.1