aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Stockhausen <stockhausen@collogia.de>2018-07-27 09:09:53 -0600
committerAlistair Strachan <astrachan@google.com>2019-01-23 22:16:08 +0000
commit11d21456d7c901647e8c4b8d9e05ea04600edf3f (patch)
tree2b000dc1ac2ff8fcc2a6430fdb8df94b5ccaaa31
parent1e6563ffd0e3905a8b2281aae7c8b7e918c92f6a (diff)
UPSTREAM: readahead: stricter check for bdi io_pages
ondemand_readahead() checks bdi->io_pages to cap the maximum pages that need to be processed. This works until the readit section. If we would do an async only readahead (async size = sync size) and target is at beginning of window we expand the pages by another get_next_ra_size() pages. Btrace for large reads shows that kernel always issues a doubled size read at the beginning of processing. Add an additional check for io_pages in the lower part of the func. The fix helps devices that hard limit bio pages and rely on proper handling of max_hw_read_sectors (e.g. older FusionIO cards). For that reason it could qualify for stable. Fixes: 9491ae4a ("mm: don't cap request size based on read-ahead setting") Change-Id: If111344b54897555085c2a6c442d697069962f11 Cc: stable@vger.kernel.org Signed-off-by: Markus Stockhausen <stockhausen@collogia.de> Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
-rw-r--r--mm/readahead.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/mm/readahead.c b/mm/readahead.c
index 655d973433b1..bf9db0fa4506 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -380,6 +380,7 @@ ondemand_readahead(struct address_space *mapping,
{
struct backing_dev_info *bdi = inode_to_bdi(mapping->host);
unsigned long max_pages = ra->ra_pages;
+ unsigned long add_pages;
pgoff_t prev_offset;
/*
@@ -469,10 +470,17 @@ readit:
* Will this read hit the readahead marker made by itself?
* If so, trigger the readahead marker hit now, and merge
* the resulted next readahead window into the current one.
+ * Take care of maximum IO pages as above.
*/
if (offset == ra->start && ra->size == ra->async_size) {
- ra->async_size = get_next_ra_size(ra, max_pages);
- ra->size += ra->async_size;
+ add_pages = get_next_ra_size(ra, max_pages);
+ if (ra->size + add_pages <= max_pages) {
+ ra->async_size = add_pages;
+ ra->size += add_pages;
+ } else {
+ ra->size = max_pages;
+ ra->async_size = max_pages >> 1;
+ }
}
return ra_submit(ra, mapping, filp);