aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2005-05-17 00:53:49 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-17 10:59:20 -0400
commitc64610ba585fabb36be78782868277f3d9741a2e (patch)
treee731ee73950ecb6969bb0d7739c03d16373c44c0
parent3c0547ba8b3bbd8b26ae35e33ac17ff51f67f78c (diff)
[PATCH] block_read_full_page() get_block() error handling fix
If block_read_full_page() detects an error when running get_block() it will run SetPageError(), then it will zero out the block in pagecache and will mark the buffer_head uptodate. So at the end of readahead we end up with a non-uptodate pagecache page which is marked PageError. But it has uptodate buffers. The pagefault code will run ClearPageError, will launch readpage a second time and block_read_full_page() will notice the uptodate buffers and will mark the page uptodate as well. We end up with an uptodate, !PageError page full of zeros and the error is lost. (It seems a little odd that filemap_nopage() runs ClearPageError(). I guess all of this adds up to meaning that for each attempted access to the page, the pagefault handler will retry the I/O. Which is good and bad. If the app is ignoring SIGBUS for some reason we could get a lot of back-to-back I/O errors.) Fix it by not marking the pagecache buffer_head as uptodate if the attempt to map that buffer to a disk block failed. Credit-to: Qu Fuping <fs@ercist.iscas.ac.cn> For reporting the bug and identifying its source. Signed-off-by: Qu Fuping <fs@ercist.iscas.ac.cn> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/buffer.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 6f88dcc6d002..7e9e409feaa7 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2094,9 +2094,12 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
2094 continue; 2094 continue;
2095 2095
2096 if (!buffer_mapped(bh)) { 2096 if (!buffer_mapped(bh)) {
2097 int err = 0;
2098
2097 fully_mapped = 0; 2099 fully_mapped = 0;
2098 if (iblock < lblock) { 2100 if (iblock < lblock) {
2099 if (get_block(inode, iblock, bh, 0)) 2101 err = get_block(inode, iblock, bh, 0);
2102 if (err)
2100 SetPageError(page); 2103 SetPageError(page);
2101 } 2104 }
2102 if (!buffer_mapped(bh)) { 2105 if (!buffer_mapped(bh)) {
@@ -2104,7 +2107,8 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
2104 memset(kaddr + i * blocksize, 0, blocksize); 2107 memset(kaddr + i * blocksize, 0, blocksize);
2105 flush_dcache_page(page); 2108 flush_dcache_page(page);
2106 kunmap_atomic(kaddr, KM_USER0); 2109 kunmap_atomic(kaddr, KM_USER0);
2107 set_buffer_uptodate(bh); 2110 if (!err)
2111 set_buffer_uptodate(bh);
2108 continue; 2112 continue;
2109 } 2113 }
2110 /* 2114 /*