]> git.itanic.dy.fi Git - linux-stable/commitdiff
fuse: lock inode unconditionally in fuse_fallocate()
authorMiklos Szeredi <mszeredi@redhat.com>
Wed, 23 Nov 2022 08:10:42 +0000 (09:10 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 Dec 2022 16:41:11 +0000 (17:41 +0100)
commit 44361e8cf9ddb23f17bdcc40ca944abf32e83e79 upstream.

file_modified() must be called with inode lock held.  fuse_fallocate()
didn't lock the inode in case of just FALLOC_KEEP_SIZE flags value, which
resulted in a kernel Warning in notify_change().

Lock the inode unconditionally, like all other fallocate implementations
do.

Reported-by: Pengfei Xu <pengfei.xu@intel.com>
Reported-and-tested-by: syzbot+462da39f0667b357c4b6@syzkaller.appspotmail.com
Fixes: 4a6f278d4827 ("fuse: add file_modified() to fallocate")
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/fuse/file.c

index 307e7dae3ab6b0a2606f91c929c9ecaf582d4e39..cc95a1c37644909bafdcb00e2e400ead1b901d48 100644 (file)
@@ -2937,11 +2937,9 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
                .mode = mode
        };
        int err;
-       bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) ||
-                          (mode & (FALLOC_FL_PUNCH_HOLE |
-                                   FALLOC_FL_ZERO_RANGE));
-
-       bool block_faults = FUSE_IS_DAX(inode) && lock_inode;
+       bool block_faults = FUSE_IS_DAX(inode) &&
+               (!(mode & FALLOC_FL_KEEP_SIZE) ||
+                (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)));
 
        if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
                     FALLOC_FL_ZERO_RANGE))
@@ -2950,22 +2948,20 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
        if (fm->fc->no_fallocate)
                return -EOPNOTSUPP;
 
-       if (lock_inode) {
-               inode_lock(inode);
-               if (block_faults) {
-                       filemap_invalidate_lock(inode->i_mapping);
-                       err = fuse_dax_break_layouts(inode, 0, 0);
-                       if (err)
-                               goto out;
-               }
+       inode_lock(inode);
+       if (block_faults) {
+               filemap_invalidate_lock(inode->i_mapping);
+               err = fuse_dax_break_layouts(inode, 0, 0);
+               if (err)
+                       goto out;
+       }
 
-               if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) {
-                       loff_t endbyte = offset + length - 1;
+       if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) {
+               loff_t endbyte = offset + length - 1;
 
-                       err = fuse_writeback_range(inode, offset, endbyte);
-                       if (err)
-                               goto out;
-               }
+               err = fuse_writeback_range(inode, offset, endbyte);
+               if (err)
+                       goto out;
        }
 
        if (!(mode & FALLOC_FL_KEEP_SIZE) &&
@@ -3015,8 +3011,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
        if (block_faults)
                filemap_invalidate_unlock(inode->i_mapping);
 
-       if (lock_inode)
-               inode_unlock(inode);
+       inode_unlock(inode);
 
        fuse_flush_time_update(inode);