mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-30 19:06:14 +00:00
[PATCH] grow_buffers() infinite loop fix
If grow_buffers() is for some reason passed a block number which wants to lie outside the maximum-addressable pagecache range (PAGE_SIZE * 4G bytes) then it will accidentally truncate `index' and will then instnatiate a page at the wrong pagecache offset. This causes __getblk_slow() to go into an infinite loop. This can happen with corrupted disks, or with software errors elsewhere. Detect that, and handle it. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
e0ab2928cc
commit
e565793386
1 changed files with 19 additions and 2 deletions
21
fs/buffer.c
21
fs/buffer.c
|
@ -1042,8 +1042,21 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
|
||||||
} while ((size << sizebits) < PAGE_SIZE);
|
} while ((size << sizebits) < PAGE_SIZE);
|
||||||
|
|
||||||
index = block >> sizebits;
|
index = block >> sizebits;
|
||||||
block = index << sizebits;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for a block which wants to lie outside our maximum possible
|
||||||
|
* pagecache index. (this comparison is done using sector_t types).
|
||||||
|
*/
|
||||||
|
if (unlikely(index != block >> sizebits)) {
|
||||||
|
char b[BDEVNAME_SIZE];
|
||||||
|
|
||||||
|
printk(KERN_ERR "%s: requested out-of-range block %llu for "
|
||||||
|
"device %s\n",
|
||||||
|
__FUNCTION__, (unsigned long long)block,
|
||||||
|
bdevname(bdev, b));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
block = index << sizebits;
|
||||||
/* Create a page with the proper size buffers.. */
|
/* Create a page with the proper size buffers.. */
|
||||||
page = grow_dev_page(bdev, block, index, size);
|
page = grow_dev_page(bdev, block, index, size);
|
||||||
if (!page)
|
if (!page)
|
||||||
|
@ -1070,12 +1083,16 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct buffer_head * bh;
|
struct buffer_head * bh;
|
||||||
|
int ret;
|
||||||
|
|
||||||
bh = __find_get_block(bdev, block, size);
|
bh = __find_get_block(bdev, block, size);
|
||||||
if (bh)
|
if (bh)
|
||||||
return bh;
|
return bh;
|
||||||
|
|
||||||
if (!grow_buffers(bdev, block, size))
|
ret = grow_buffers(bdev, block, size);
|
||||||
|
if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
if (ret == 0)
|
||||||
free_more_memory();
|
free_more_memory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue