udf: fix possible leakage of blocks
We have to take care that when we call udf_discard_prealloc() from udf_clear_inode() we have to write inode ourselves afterwards (otherwise, some changes might be lost leading to leakage of blocks, use of free blocks or improperly aligned extents). Also udf_discard_prealloc() does two different things - it removes preallocated blocks and truncates the last extent to exactly match i_size. We move the latter functionality to udf_truncate_tail_extent(), call udf_discard_prealloc() when last reference to a file is dropped and call udf_truncate_tail_extent() when inode is being removed from inode cache (udf_clear_inode() call). We cannot call udf_truncate_tail_extent() earlier as subsequent open+write would find the last block of the file mapped and happily write to the end of it, although the last extent says it's shorter. [akpm@linux-foundation.org: Make checkpatch.pl happier] Signed-off-by: Jan Kara <jack@suse.cz> Cc: Eric Sandeen <sandeen@sandeen.net> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
@@ -100,14 +100,23 @@ no_delete:
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are going to release inode from memory, we discard preallocation and
|
||||
* truncate last inode extent to proper length. We could use drop_inode() but
|
||||
* it's called under inode_lock and thus we cannot mark inode dirty there. We
|
||||
* use clear_inode() but we have to make sure to write inode as it's not written
|
||||
* automatically.
|
||||
*/
|
||||
void udf_clear_inode(struct inode *inode)
|
||||
{
|
||||
if (!(inode->i_sb->s_flags & MS_RDONLY)) {
|
||||
lock_kernel();
|
||||
/* Discard preallocation for directories, symlinks, etc. */
|
||||
udf_discard_prealloc(inode);
|
||||
udf_truncate_tail_extent(inode);
|
||||
unlock_kernel();
|
||||
write_inode_now(inode, 1);
|
||||
}
|
||||
|
||||
kfree(UDF_I_DATA(inode));
|
||||
UDF_I_DATA(inode) = NULL;
|
||||
}
|
||||
|
Reference in New Issue
Block a user