diff options
author | Jan Kara <jack@suse.cz> | 2007-05-06 17:49:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:12:52 -0400 |
commit | ec0f16372277052a29a6c17527c6cae5e898b3fd (patch) | |
tree | 35636edac6ed01baf301f3aca96f090caae82c9d | |
parent | b813e931b4c8235bb42e301096ea97dbdee3e8fe (diff) |
readahead: improve heuristic detecting sequential reads
Introduce ra.offset and store in it an offset where the previous read
ended. This way we can detect whether reads are really sequential (and
thus we should not mark the page as accessed repeatedly) or whether they
are random and just happen to be in the same page (and the page should
really be marked accessed again).
Signed-off-by: Jan Kara <jack@suse.cz>
Acked-by: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: WU Fengguang <wfg@mail.ustc.edu.cn>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | mm/filemap.c | 9 | ||||
-rw-r--r-- | mm/readahead.c | 3 |
3 files changed, 10 insertions, 3 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index 7c0077f06e24..0949e243b8b9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -702,6 +702,7 @@ struct file_ra_state { | |||
702 | unsigned long ra_pages; /* Maximum readahead window */ | 702 | unsigned long ra_pages; /* Maximum readahead window */ |
703 | unsigned long mmap_hit; /* Cache hit stat for mmap accesses */ | 703 | unsigned long mmap_hit; /* Cache hit stat for mmap accesses */ |
704 | unsigned long mmap_miss; /* Cache miss stat for mmap accesses */ | 704 | unsigned long mmap_miss; /* Cache miss stat for mmap accesses */ |
705 | unsigned int offset; /* Offset where last read() ended in a page */ | ||
705 | }; | 706 | }; |
706 | #define RA_FLAG_MISS 0x01 /* a cache miss occured against this file */ | 707 | #define RA_FLAG_MISS 0x01 /* a cache miss occured against this file */ |
707 | #define RA_FLAG_INCACHE 0x02 /* file is already in cache */ | 708 | #define RA_FLAG_INCACHE 0x02 /* file is already in cache */ |
diff --git a/mm/filemap.c b/mm/filemap.c index cbea95a25283..07f5b77114a3 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -868,6 +868,7 @@ void do_generic_mapping_read(struct address_space *mapping, | |||
868 | unsigned long last_index; | 868 | unsigned long last_index; |
869 | unsigned long next_index; | 869 | unsigned long next_index; |
870 | unsigned long prev_index; | 870 | unsigned long prev_index; |
871 | unsigned int prev_offset; | ||
871 | loff_t isize; | 872 | loff_t isize; |
872 | struct page *cached_page; | 873 | struct page *cached_page; |
873 | int error; | 874 | int error; |
@@ -877,6 +878,7 @@ void do_generic_mapping_read(struct address_space *mapping, | |||
877 | index = *ppos >> PAGE_CACHE_SHIFT; | 878 | index = *ppos >> PAGE_CACHE_SHIFT; |
878 | next_index = index; | 879 | next_index = index; |
879 | prev_index = ra.prev_page; | 880 | prev_index = ra.prev_page; |
881 | prev_offset = ra.offset; | ||
880 | last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT; | 882 | last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT; |
881 | offset = *ppos & ~PAGE_CACHE_MASK; | 883 | offset = *ppos & ~PAGE_CACHE_MASK; |
882 | 884 | ||
@@ -924,10 +926,10 @@ page_ok: | |||
924 | flush_dcache_page(page); | 926 | flush_dcache_page(page); |
925 | 927 | ||
926 | /* | 928 | /* |
927 | * When (part of) the same page is read multiple times | 929 | * When a sequential read accesses a page several times, |
928 | * in succession, only mark it as accessed the first time. | 930 | * only mark it as accessed the first time. |
929 | */ | 931 | */ |
930 | if (prev_index != index) | 932 | if (prev_index != index || offset != prev_offset) |
931 | mark_page_accessed(page); | 933 | mark_page_accessed(page); |
932 | prev_index = index; | 934 | prev_index = index; |
933 | 935 | ||
@@ -945,6 +947,7 @@ page_ok: | |||
945 | offset += ret; | 947 | offset += ret; |
946 | index += offset >> PAGE_CACHE_SHIFT; | 948 | index += offset >> PAGE_CACHE_SHIFT; |
947 | offset &= ~PAGE_CACHE_MASK; | 949 | offset &= ~PAGE_CACHE_MASK; |
950 | prev_offset = ra.offset = offset; | ||
948 | 951 | ||
949 | page_cache_release(page); | 952 | page_cache_release(page); |
950 | if (ret == nr && desc->count) | 953 | if (ret == nr && desc->count) |
diff --git a/mm/readahead.c b/mm/readahead.c index 93d9ee692fd8..0a6fed9d365c 100644 --- a/mm/readahead.c +++ b/mm/readahead.c | |||
@@ -207,6 +207,8 @@ out: | |||
207 | * If page_cache_readahead sees that it is again being called for | 207 | * If page_cache_readahead sees that it is again being called for |
208 | * a page which it just looked at, it can return immediately without | 208 | * a page which it just looked at, it can return immediately without |
209 | * making any state changes. | 209 | * making any state changes. |
210 | * offset: Offset in the prev_page where the last read ended - used for | ||
211 | * detection of sequential file reading. | ||
210 | * ahead_start, | 212 | * ahead_start, |
211 | * ahead_size: Together, these form the "ahead window". | 213 | * ahead_size: Together, these form the "ahead window". |
212 | * ra_pages: The externally controlled max readahead for this fd. | 214 | * ra_pages: The externally controlled max readahead for this fd. |
@@ -473,6 +475,7 @@ page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, | |||
473 | /* Note that prev_page == -1 if it is a first read */ | 475 | /* Note that prev_page == -1 if it is a first read */ |
474 | sequential = (offset == ra->prev_page + 1); | 476 | sequential = (offset == ra->prev_page + 1); |
475 | ra->prev_page = offset; | 477 | ra->prev_page = offset; |
478 | ra->offset = 0; | ||
476 | 479 | ||
477 | max = get_max_readahead(ra); | 480 | max = get_max_readahead(ra); |
478 | newsize = min(req_size, max); | 481 | newsize = min(req_size, max); |