diff options
author | Shaohua Li <shaohua.li@intel.com> | 2012-02-03 18:37:17 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-02-03 19:16:41 -0500 |
commit | 3deaa7190a8da38453c4fabd9dec7f66d17fff67 (patch) | |
tree | 23c522d5661bf7e73a39718eaf4eb547cf02b086 /mm/filemap.c | |
parent | 55ca6140e9bb307efc97a9301a4f501de02a6fd6 (diff) |
readahead: fix pipeline break caused by block plug
Herbert Poetzl reported a performance regression since 2.6.39. The test
is a simple dd read, but with big block size. The reason is:
T1: ra (A, A+128k), (A+128k, A+256k)
T2: lock_page for page A, submit the 256k
T3: hit page A+128K, ra (A+256k, A+384). the range isn't submitted
because of plug and there isn't any lock_page till we hit page A+256k
because all pages from A to A+256k is in memory
T4: hit page A+256k, ra (A+384, A+ 512). Because of plug, the range isn't
submitted again.
T5: lock_page A+256k, so (A+256k, A+512k) will be submitted. The task is
waitting for (A+256k, A+512k) finish.
There is no request to disk in T3 and T4, so readahead pipeline breaks.
We really don't need block plug for generic_file_aio_read() for buffered
I/O. The readahead already has plug and has fine grained control when I/O
should be submitted. Deleting plug for buffered I/O fixes the regression.
One side effect is plug makes the request size 256k, the size is 128k
without it. This is because default ra size is 128k and not a reason we
need plug here.
Vivek said:
: We submit some readahead IO to device request queue but because of nested
: plug, queue never gets unplugged. When read logic reaches a page which is
: not in page cache, it waits for page to be read from the disk
: (lock_page_killable()) and that time we flush the plug list.
:
: So effectively read ahead logic is kind of broken in parts because of
: nested plugging. Removing top level plug (generic_file_aio_read()) for
: buffered reads, will allow unplugging queue earlier for readahead.
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Reported-by: Herbert Poetzl <herbert@13thfloor.at>
Tested-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 97f49ed35bd2..b66275757c28 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1400,15 +1400,12 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1400 | unsigned long seg = 0; | 1400 | unsigned long seg = 0; |
1401 | size_t count; | 1401 | size_t count; |
1402 | loff_t *ppos = &iocb->ki_pos; | 1402 | loff_t *ppos = &iocb->ki_pos; |
1403 | struct blk_plug plug; | ||
1404 | 1403 | ||
1405 | count = 0; | 1404 | count = 0; |
1406 | retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); | 1405 | retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); |
1407 | if (retval) | 1406 | if (retval) |
1408 | return retval; | 1407 | return retval; |
1409 | 1408 | ||
1410 | blk_start_plug(&plug); | ||
1411 | |||
1412 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | 1409 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ |
1413 | if (filp->f_flags & O_DIRECT) { | 1410 | if (filp->f_flags & O_DIRECT) { |
1414 | loff_t size; | 1411 | loff_t size; |
@@ -1424,8 +1421,12 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1424 | retval = filemap_write_and_wait_range(mapping, pos, | 1421 | retval = filemap_write_and_wait_range(mapping, pos, |
1425 | pos + iov_length(iov, nr_segs) - 1); | 1422 | pos + iov_length(iov, nr_segs) - 1); |
1426 | if (!retval) { | 1423 | if (!retval) { |
1424 | struct blk_plug plug; | ||
1425 | |||
1426 | blk_start_plug(&plug); | ||
1427 | retval = mapping->a_ops->direct_IO(READ, iocb, | 1427 | retval = mapping->a_ops->direct_IO(READ, iocb, |
1428 | iov, pos, nr_segs); | 1428 | iov, pos, nr_segs); |
1429 | blk_finish_plug(&plug); | ||
1429 | } | 1430 | } |
1430 | if (retval > 0) { | 1431 | if (retval > 0) { |
1431 | *ppos = pos + retval; | 1432 | *ppos = pos + retval; |
@@ -1481,7 +1482,6 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1481 | break; | 1482 | break; |
1482 | } | 1483 | } |
1483 | out: | 1484 | out: |
1484 | blk_finish_plug(&plug); | ||
1485 | return retval; | 1485 | return retval; |
1486 | } | 1486 | } |
1487 | EXPORT_SYMBOL(generic_file_aio_read); | 1487 | EXPORT_SYMBOL(generic_file_aio_read); |