diff options
author | Evgeniy Dushistov <dushistov@mail.ru> | 2006-07-01 04:36:24 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-01 09:56:03 -0700 |
commit | 10e5dce07e6f8f9cea1b54161a888bb099484f88 (patch) | |
tree | 9c7949cf82763344d86ae302748f8e1d278b565a /fs/ufs/util.c | |
parent | eb28931e4a2c89e53d2b0c1a02a843240bff0806 (diff) | |
download | linux-10e5dce07e6f8f9cea1b54161a888bb099484f88.tar.gz linux-10e5dce07e6f8f9cea1b54161a888bb099484f88.tar.bz2 linux-10e5dce07e6f8f9cea1b54161a888bb099484f88.zip |
[PATCH] ufs: truncate should allocate block for last byte
This patch fixes buggy behaviour of UFS
in such kind of scenario:
open(, O_TRUNC...)
ftruncate(, 1024)
ftruncate(, 0)
Such a scenario causes ufs_panic and remount read-only. This happen
because of according to specification UFS should always allocate block for
last byte, and many parts of our implementation rely on this, but
`ufs_truncate' doesn't care about this.
To make possible return error code and to know about old size, this patch
removes `truncate' from ufs inode_operations and uses `setattr' method to
call ufs_truncate.
Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/ufs/util.c')
-rw-r--r-- | fs/ufs/util.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/fs/ufs/util.c b/fs/ufs/util.c index a2f13f45708b..337cf2c46d10 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -233,3 +233,57 @@ ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev else ufsi->i_u1.i_data[0] = fs32; } + +/** + * ufs_get_locked_page() - locate, pin and lock a pagecache page, if not exist + * read it from disk. + * @mapping: the address_space to search + * @index: the page index + * + * Locates the desired pagecache page, if not exist we'll read it, + * locks it, increments its reference + * count and returns its address. + * + */ + +struct page *ufs_get_locked_page(struct address_space *mapping, + pgoff_t index) +{ + struct page *page; + +try_again: + page = find_lock_page(mapping, index); + if (!page) { + page = read_cache_page(mapping, index, + (filler_t*)mapping->a_ops->readpage, + NULL); + if (IS_ERR(page)) { + printk(KERN_ERR "ufs_change_blocknr: " + "read_cache_page error: ino %lu, index: %lu\n", + mapping->host->i_ino, index); + goto out; + } + + lock_page(page); + + if (!PageUptodate(page) || PageError(page)) { + unlock_page(page); + page_cache_release(page); + + printk(KERN_ERR "ufs_change_blocknr: " + "can not read page: ino %lu, index: %lu\n", + mapping->host->i_ino, index); + + page = ERR_PTR(-EIO); + goto out; + } + } + + if (unlikely(!page->mapping || !page_has_buffers(page))) { + unlock_page(page); + page_cache_release(page); + goto try_again;/*we really need these buffers*/ + } +out: + return page; +} |