From 63d0f0a3c7e1281fd79268a8d988167eff607fb6 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 Nov 2013 15:07:09 -0800 Subject: mm/readahead.c:do_readhead(): don't check for ->readpage The callee force_page_cache_readahead() already does this and unlike do_readahead(), force_page_cache_readahead() remembers to check for ->readpages() as well. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/readahead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mm/readahead.c') diff --git a/mm/readahead.c b/mm/readahead.c index e4ed04149785..50241836fe82 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -569,7 +569,7 @@ static ssize_t do_readahead(struct address_space *mapping, struct file *filp, pgoff_t index, unsigned long nr) { - if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage) + if (!mapping || !mapping->a_ops) return -EINVAL; force_page_cache_readahead(mapping, filp, index, nr); -- cgit v1.2.3-70-g09d2 From af248a0c67457e5c6d2bcf288f07b4b2ed064f1f Mon Sep 17 00:00:00 2001 From: Damien Ramonda Date: Tue, 12 Nov 2013 15:08:16 -0800 Subject: readahead: fix sequential read cache miss detection The kernel's readahead algorithm sometimes interprets random read accesses as sequential and triggers unnecessary data prefecthing from storage device (impacting random read average latency). In order to identify sequential cache read misses, the readahead algorithm intends to check whether offset - previous offset == 1 (trivial sequential reads) or offset - previous offset == 0 (sequential reads not aligned on page boundary): if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL) The current offset is stored in the "offset" variable of type "pgoff_t" (unsigned long), while previous offset is stored in "ra->prev_pos" of type "loff_t" (long long). Therefore, operands of the if statement are implicitly converted to type long long. Consequently, when previous offset > current offset (which happens on random pattern), the if condition is true and access is wrongly interpeted as sequential. An unnecessary data prefetching is triggered, impacting the average random read latency. Storing the previous offset value in a "pgoff_t" variable (unsigned long) fixes the sequential read detection logic. Signed-off-by: Damien Ramonda Reviewed-by: Fengguang Wu Acked-by: Pierre Tardy Acked-by: David Cohen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/readahead.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'mm/readahead.c') diff --git a/mm/readahead.c b/mm/readahead.c index 50241836fe82..7cdbb44aa90b 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -401,6 +401,7 @@ ondemand_readahead(struct address_space *mapping, unsigned long req_size) { unsigned long max = max_sane_readahead(ra->ra_pages); + pgoff_t prev_offset; /* * start of file @@ -452,8 +453,11 @@ ondemand_readahead(struct address_space *mapping, /* * sequential cache miss + * trivial case: (offset - prev_offset) == 1 + * unaligned reads: (offset - prev_offset) == 0 */ - if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL) + prev_offset = (unsigned long long)ra->prev_pos >> PAGE_CACHE_SHIFT; + if (offset - prev_offset <= 1UL) goto initial_readahead; /* -- cgit v1.2.3-70-g09d2