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 { unsigned long ra_pages; /* Maximum readahead window */ unsigned long mmap_hit; /* Cache hit stat for mmap accesses */ unsigned long mmap_miss; /* Cache miss stat for mmap accesses */ + unsigned int offset; /* Offset where last read() ended in a page */ }; #define RA_FLAG_MISS 0x01 /* a cache miss occured against this file */ #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, unsigned long last_index; unsigned long next_index; unsigned long prev_index; + unsigned int prev_offset; loff_t isize; struct page *cached_page; int error; @@ -877,6 +878,7 @@ void do_generic_mapping_read(struct address_space *mapping, index = *ppos >> PAGE_CACHE_SHIFT; next_index = index; prev_index = ra.prev_page; + prev_offset = ra.offset; last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT; offset = *ppos & ~PAGE_CACHE_MASK; @@ -924,10 +926,10 @@ void do_generic_mapping_read(struct address_space *mapping, flush_dcache_page(page); /* - * When (part of) the same page is read multiple times - * in succession, only mark it as accessed the first time. + * When a sequential read accesses a page several times, + * only mark it as accessed the first time. */ - if (prev_index != index) + if (prev_index != index || offset != prev_offset) mark_page_accessed(page); prev_index = index; @@ -945,6 +947,7 @@ void do_generic_mapping_read(struct address_space *mapping, offset += ret; index += offset >> PAGE_CACHE_SHIFT; offset &= ~PAGE_CACHE_MASK; + prev_offset = ra.offset = offset; page_cache_release(page); 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 @@ static int read_pages(struct address_space *mapping, struct file *filp, * If page_cache_readahead sees that it is again being called for * a page which it just looked at, it can return immediately without * making any state changes. + * offset: Offset in the prev_page where the last read ended - used for + * detection of sequential file reading. * ahead_start, * ahead_size: Together, these form the "ahead window". * 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, /* Note that prev_page == -1 if it is a first read */ sequential = (offset == ra->prev_page + 1); ra->prev_page = offset; + ra->offset = 0; max = get_max_readahead(ra); newsize = min(req_size, max);