summaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2014-04-12 09:56:41 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-04-12 09:56:41 -0400
commit23fffa925ea2c9a2bcb1a4453e2c542635aa3545 (patch)
treeada18ccc75346035bea8c684344fa2da6eac9f5b /fs/ext4/extents.c
parent8fc61d92630d1c96057a94c61e1643475045b25b (diff)
fs: move falloc collapse range check into the filesystem methods
Currently in do_fallocate in collapse range case we're checking whether offset + len is not bigger than i_size. However there is nothing which would prevent i_size from changing so the check is pointless. It should be done in the file system itself and the file system needs to make sure that i_size is not going to change. The i_size check for the other fallocate modes are also done in the filesystems. As it is now we can easily crash the kernel by having two processes doing truncate and fallocate collapse range at the same time. This can be reproduced on ext4 and it is theoretically possible on xfs even though I was not able to trigger it with this simple test. This commit removes the check from do_fallocate and adds it to the file system. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Acked-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r--fs/ext4/extents.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ed4ec48239b6..ac5460d0d133 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -5368,8 +5368,6 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
5368 loff_t new_size; 5368 loff_t new_size;
5369 int ret; 5369 int ret;
5370 5370
5371 BUG_ON(offset + len > i_size_read(inode));
5372
5373 /* Collapse range works only on fs block size aligned offsets. */ 5371 /* Collapse range works only on fs block size aligned offsets. */
5374 if (offset & (EXT4_BLOCK_SIZE(sb) - 1) || 5372 if (offset & (EXT4_BLOCK_SIZE(sb) - 1) ||
5375 len & (EXT4_BLOCK_SIZE(sb) - 1)) 5373 len & (EXT4_BLOCK_SIZE(sb) - 1))
@@ -5398,6 +5396,15 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
5398 /* Take mutex lock */ 5396 /* Take mutex lock */
5399 mutex_lock(&inode->i_mutex); 5397 mutex_lock(&inode->i_mutex);
5400 5398
5399 /*
5400 * There is no need to overlap collapse range with EOF, in which case
5401 * it is effectively a truncate operation
5402 */
5403 if (offset + len >= i_size_read(inode)) {
5404 ret = -EINVAL;
5405 goto out_mutex;
5406 }
5407
5401 if (IS_SWAPFILE(inode)) { 5408 if (IS_SWAPFILE(inode)) {
5402 ret = -ETXTBSY; 5409 ret = -ETXTBSY;
5403 goto out_mutex; 5410 goto out_mutex;