aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf/inode.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2007-06-16 13:16:14 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-06-16 16:16:16 -0400
commit74584ae509befc2ed711810e7df4b075473869b2 (patch)
tree9cb1b4a06b8583895c96d9b1a959d81df3950a06 /fs/udf/inode.c
parent4b356be019d0c28f67af02809df7072c1c8f7d32 (diff)
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>
Diffstat (limited to 'fs/udf/inode.c')
-rw-r--r--fs/udf/inode.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 1f0129405cf4..bf7de0bdbab3 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -100,14 +100,23 @@ no_delete:
100 clear_inode(inode); 100 clear_inode(inode);
101} 101}
102 102
103/*
104 * If we are going to release inode from memory, we discard preallocation and
105 * truncate last inode extent to proper length. We could use drop_inode() but
106 * it's called under inode_lock and thus we cannot mark inode dirty there. We
107 * use clear_inode() but we have to make sure to write inode as it's not written
108 * automatically.
109 */
103void udf_clear_inode(struct inode *inode) 110void udf_clear_inode(struct inode *inode)
104{ 111{
105 if (!(inode->i_sb->s_flags & MS_RDONLY)) { 112 if (!(inode->i_sb->s_flags & MS_RDONLY)) {
106 lock_kernel(); 113 lock_kernel();
114 /* Discard preallocation for directories, symlinks, etc. */
107 udf_discard_prealloc(inode); 115 udf_discard_prealloc(inode);
116 udf_truncate_tail_extent(inode);
108 unlock_kernel(); 117 unlock_kernel();
118 write_inode_now(inode, 1);
109 } 119 }
110
111 kfree(UDF_I_DATA(inode)); 120 kfree(UDF_I_DATA(inode));
112 UDF_I_DATA(inode) = NULL; 121 UDF_I_DATA(inode) = NULL;
113} 122}