diff options
author | Evgeniy Dushistov <dushistov@mail.ru> | 2006-07-01 07:36:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-01 12:56:03 -0400 |
commit | 10e5dce07e6f8f9cea1b54161a888bb099484f88 (patch) | |
tree | 9c7949cf82763344d86ae302748f8e1d278b565a /fs/ufs/util.c | |
parent | eb28931e4a2c89e53d2b0c1a02a843240bff0806 (diff) |
[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 | |||
233 | else | 233 | else |
234 | ufsi->i_u1.i_data[0] = fs32; | 234 | ufsi->i_u1.i_data[0] = fs32; |
235 | } | 235 | } |
236 | |||
237 | /** | ||
238 | * ufs_get_locked_page() - locate, pin and lock a pagecache page, if not exist | ||
239 | * read it from disk. | ||
240 | * @mapping: the address_space to search | ||
241 | * @index: the page index | ||
242 | * | ||
243 | * Locates the desired pagecache page, if not exist we'll read it, | ||
244 | * locks it, increments its reference | ||
245 | * count and returns its address. | ||
246 | * | ||
247 | */ | ||
248 | |||
249 | struct page *ufs_get_locked_page(struct address_space *mapping, | ||
250 | pgoff_t index) | ||
251 | { | ||
252 | struct page *page; | ||
253 | |||
254 | try_again: | ||
255 | page = find_lock_page(mapping, index); | ||
256 | if (!page) { | ||
257 | page = read_cache_page(mapping, index, | ||
258 | (filler_t*)mapping->a_ops->readpage, | ||
259 | NULL); | ||
260 | if (IS_ERR(page)) { | ||
261 | printk(KERN_ERR "ufs_change_blocknr: " | ||
262 | "read_cache_page error: ino %lu, index: %lu\n", | ||
263 | mapping->host->i_ino, index); | ||
264 | goto out; | ||
265 | } | ||
266 | |||
267 | lock_page(page); | ||
268 | |||
269 | if (!PageUptodate(page) || PageError(page)) { | ||
270 | unlock_page(page); | ||
271 | page_cache_release(page); | ||
272 | |||
273 | printk(KERN_ERR "ufs_change_blocknr: " | ||
274 | "can not read page: ino %lu, index: %lu\n", | ||
275 | mapping->host->i_ino, index); | ||
276 | |||
277 | page = ERR_PTR(-EIO); | ||
278 | goto out; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | if (unlikely(!page->mapping || !page_has_buffers(page))) { | ||
283 | unlock_page(page); | ||
284 | page_cache_release(page); | ||
285 | goto try_again;/*we really need these buffers*/ | ||
286 | } | ||
287 | out: | ||
288 | return page; | ||
289 | } | ||