mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-14 04:41:26 +00:00
[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>
This commit is contained in:
parent
3c0547ba8b
commit
c64610ba58
@ -2094,9 +2094,12 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
|
||||
continue;
|
||||
|
||||
if (!buffer_mapped(bh)) {
|
||||
int err = 0;
|
||||
|
||||
fully_mapped = 0;
|
||||
if (iblock < lblock) {
|
||||
if (get_block(inode, iblock, bh, 0))
|
||||
err = get_block(inode, iblock, bh, 0);
|
||||
if (err)
|
||||
SetPageError(page);
|
||||
}
|
||||
if (!buffer_mapped(bh)) {
|
||||
@ -2104,7 +2107,8 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
|
||||
memset(kaddr + i * blocksize, 0, blocksize);
|
||||
flush_dcache_page(page);
|
||||
kunmap_atomic(kaddr, KM_USER0);
|
||||
set_buffer_uptodate(bh);
|
||||
if (!err)
|
||||
set_buffer_uptodate(bh);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user