aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorRam Pai <linuxram@us.ibm.com>2004-09-07 17:50:22 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-09-07 17:50:22 -0700
commit5c689659b4056c0b4f70d10654d2c713fe2cf3d6 (patch)
treefb33374ce4ac71e07bd7991041c24f5ab2c759c2 /mm
parent22141f0513da328f8f4e405953e5e52fb7c4e65a (diff)
downloadhistory-5c689659b4056c0b4f70d10654d2c713fe2cf3d6.tar.gz
[PATCH] filemap read() fix
Fix the do_generic_file_read()-reads-one-page-too-many-bug for the fifth time. This patch combines the best features from Nick's patch and also makes index and end_index consistent. (i.e index 'n' covers n*PAGE_SIZE to ((n+1)PAGE_SIZE)-1. I did not feel comfortable with the way index and end_index represented different ranges. It was like comparing apples with oranges. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/filemap.c40
1 files changed, 27 insertions, 13 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index dfbc5e093b6692..78e18b7639b6aa 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -722,7 +722,10 @@ void do_generic_mapping_read(struct address_space *mapping,
offset = *ppos & ~PAGE_CACHE_MASK;
isize = i_size_read(inode);
- end_index = isize >> PAGE_CACHE_SHIFT;
+ if (!isize)
+ goto out;
+
+ end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
if (index > end_index)
goto out;
@@ -730,6 +733,16 @@ void do_generic_mapping_read(struct address_space *mapping,
struct page *page;
unsigned long nr, ret;
+ /* nr is the maximum number of bytes to copy from this page */
+ nr = PAGE_CACHE_SIZE;
+ if (index == end_index) {
+ nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
+ if (nr <= offset) {
+ goto out;
+ }
+ }
+ nr = nr - offset;
+
cond_resched();
page_cache_readahead(mapping, &ra, filp, index);
@@ -742,16 +755,6 @@ find_page:
if (!PageUptodate(page))
goto page_not_up_to_date;
page_ok:
- /* nr is the maximum number of bytes to copy from this page */
- nr = PAGE_CACHE_SIZE;
- if (index == end_index) {
- nr = isize & ~PAGE_CACHE_MASK;
- if (nr <= offset) {
- page_cache_release(page);
- goto out;
- }
- }
- nr = nr - offset;
/* If users can be writing to this page using arbitrary
* virtual addresses, take care about potential aliasing
@@ -827,11 +830,22 @@ readpage:
* another truncate extends the file - this is desired though).
*/
isize = i_size_read(inode);
- end_index = isize >> PAGE_CACHE_SHIFT;
- if (index > end_index) {
+ end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
+ if (unlikely(!isize || index > end_index)) {
page_cache_release(page);
goto out;
}
+
+ /* nr is the maximum number of bytes to copy from this page */
+ nr = PAGE_CACHE_SIZE;
+ if (index == end_index) {
+ nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
+ if (nr <= offset) {
+ page_cache_release(page);
+ goto out;
+ }
+ }
+ nr = nr - offset;
goto page_ok;
readpage_error: