add patch add-fallocate-mode-blocking-for-debugging
[ext4-patch-queue.git] / remove-i_size-check-from-do_fallocate
blob44ef8f43b6f481916070f7b8293e252dcb485533
1 fs: remove i_size check from do_fallocate
3 From: Lukas Czerner <lczerner@redhat.com>
5 Currently in do_fallocate in collapse range case we're checking whether
6 offset + len is not bigger than i_size. However there is nothing which
7 would prevent i_size from changing so the check is pointless. It should
8 be done in the file system itself and the file system needs to make sure
9 that i_size is not going to change.
11 As it is now we can easily crash kernel by having two processes doing
12 truncate and fallocate collapse range at the same time. This can be
13 reproduced on ext4 and it is theoretically possible on xfs even though I
14 was not able to trigger it with this simple test.
16 This commit removes the check from do_fallocate and adds it to the file
17 system.
19 Signed-off-by: Lukas Czerner <lczerner@redhat.com>
20 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
21 ---
22  fs/ext4/extents.c | 11 +++++++++--
23  fs/open.c         |  8 --------
24  fs/xfs/xfs_file.c | 10 +++++++++-
25  3 files changed, 18 insertions(+), 11 deletions(-)
27 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
28 index 0177150..ff823b7 100644
29 --- a/fs/ext4/extents.c
30 +++ b/fs/ext4/extents.c
31 @@ -5364,8 +5364,6 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
32         loff_t new_size;
33         int ret;
35 -       BUG_ON(offset + len > i_size_read(inode));
37         /* Collapse range works only on fs block size aligned offsets. */
38         if (offset & (EXT4_BLOCK_SIZE(sb) - 1) ||
39             len & (EXT4_BLOCK_SIZE(sb) - 1))
40 @@ -5387,6 +5385,15 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
41         /* Take mutex lock */
42         mutex_lock(&inode->i_mutex);
44 +       /*
45 +        * There is no need to overlap collapse range with EOF, in which case
46 +        * it is effectively a truncate operation
47 +        */
48 +       if (offset + len >= i_size_read(inode)) {
49 +               ret = -EINVAL;
50 +               goto out_mutex;
51 +       }
53         if (IS_SWAPFILE(inode)) {
54                 ret = -ETXTBSY;
55                 goto out_mutex;
56 diff --git a/fs/open.c b/fs/open.c
57 index 7882ff5..14af6be 100644
58 --- a/fs/open.c
59 +++ b/fs/open.c
60 @@ -287,14 +287,6 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
61         if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
62                 return -EFBIG;
64 -       /*
65 -        * There is no need to overlap collapse range with EOF, in which case
66 -        * it is effectively a truncate operation
67 -        */
68 -       if ((mode & FALLOC_FL_COLLAPSE_RANGE) &&
69 -           (offset + len >= i_size_read(inode)))
70 -               return -EINVAL;
72         if (!file->f_op->fallocate)
73                 return -EOPNOTSUPP;
75 diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
76 index 003c005..4ba0ae9 100644
77 --- a/fs/xfs/xfs_file.c
78 +++ b/fs/xfs/xfs_file.c
79 @@ -840,7 +840,15 @@ xfs_file_fallocate(
80                         goto out_unlock;
81                 }
83 -               ASSERT(offset + len < i_size_read(inode));
84 +               /*
85 +                * There is no need to overlap collapse range with EOF,
86 +                * in which case it is effectively a truncate operation
87 +                */
88 +               if (offset + len >= i_size_read(inode)) {
89 +                       error = -EINVAL;
90 +                       goto out_unlock;
91 +               }
93                 new_size = i_size_read(inode) - len;
95                 error = xfs_collapse_file_space(ip, offset, len);
96 -- 
97 1.8.3.1
100 To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
101 the body of a message to majordomo@vger.kernel.org
102 More majordomo info at  http://vger.kernel.org/majordomo-info.html