Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Nov 2018 03:19:49 +0000 (20:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 2 Nov 2018 03:19:49 +0000 (20:19 -0700)
Pull misc vfs updates from Al Viro:
 "No common topic, really - a handful of assorted stuff; the least
  trivial bits are Mark's dedupe patches"

* 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  fs/exofs: only use true/false for asignment of bool type variable
  fs/exofs: fix potential memory leak in mount option parsing
  Delete invalid assignment statements in do_sendfile
  iomap: remove duplicated include from iomap.c
  vfs: dedupe should return EPERM if permission is not granted
  vfs: allow dedupe of user owned read-only files
  ntfs: don't open-code ERR_CAST
  ext4: don't open-code ERR_CAST

1  2 
fs/ext4/namei.c
fs/iomap.c
fs/read_write.c

diff --combined fs/ext4/namei.c
index 67a38532032ae89cfcbaec35fe139992cbf2875e,c31717e343d08fd29ffca9b0d72ae41a24782967..17adcb16a9c85f8fee50f2796ed10c79f7e32cd7
@@@ -1556,7 -1556,7 +1556,7 @@@ static struct dentry *ext4_lookup(struc
  
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
        if (IS_ERR(bh))
-               return (struct dentry *) bh;
+               return ERR_CAST(bh);
        inode = NULL;
        if (bh) {
                __u32 ino = le32_to_cpu(de->inode);
@@@ -1600,7 -1600,7 +1600,7 @@@ struct dentry *ext4_get_parent(struct d
  
        bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL);
        if (IS_ERR(bh))
-               return (struct dentry *) bh;
+               return ERR_CAST(bh);
        if (!bh)
                return ERR_PTR(-ENOENT);
        ino = le32_to_cpu(de->inode);
@@@ -2261,7 -2261,7 +2261,7 @@@ again
                        dxroot->info.indirect_levels += 1;
                        dxtrace(printk(KERN_DEBUG
                                       "Creating %d level index...\n",
 -                                     info->indirect_levels));
 +                                     dxroot->info.indirect_levels));
                        err = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
                        if (err)
                                goto journal_error;
@@@ -3478,12 -3478,6 +3478,12 @@@ static int ext4_rename(struct inode *ol
        int credits;
        u8 old_file_type;
  
 +      if (new.inode && new.inode->i_nlink == 0) {
 +              EXT4_ERROR_INODE(new.inode,
 +                               "target of rename is already freed");
 +              return -EFSCORRUPTED;
 +      }
 +
        if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) &&
            (!projid_eq(EXT4_I(new_dir)->i_projid,
                        EXT4_I(old_dentry->d_inode)->i_projid)))
diff --combined fs/iomap.c
index 970ee3964e98a2a85932dc8d0e4532ea60ce6b59,ef26c2225c931b76c9385fe98c645fa1f89e2ae5..64ce240217a18985dd0510fd968b257dce214cd4
@@@ -30,7 -30,6 +30,6 @@@
  #include <linux/task_io_accounting_ops.h>
  #include <linux/dax.h>
  #include <linux/sched/signal.h>
- #include <linux/swap.h>
  
  #include "internal.h"
  
@@@ -1051,13 -1050,12 +1050,13 @@@ iomap_page_mkwrite_actor(struct inode *
        } else {
                WARN_ON_ONCE(!PageUptodate(page));
                iomap_page_create(inode, page);
 +              set_page_dirty(page);
        }
  
        return length;
  }
  
 -int iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops)
 +vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops)
  {
        struct page *page = vmf->page;
        struct inode *inode = file_inode(vmf->vma->vm_file);
                length -= ret;
        }
  
 -      set_page_dirty(page);
        wait_for_stable_page(page);
        return VM_FAULT_LOCKED;
  out_unlock:
@@@ -1795,7 -1794,7 +1794,7 @@@ iomap_dio_rw(struct kiocb *iocb, struc
                if (pos >= dio->i_size)
                        goto out_free_dio;
  
 -              if (iter->type == ITER_IOVEC)
 +              if (iter_is_iovec(iter) && iov_iter_rw(iter) == READ)
                        dio->flags |= IOMAP_DIO_DIRTY;
        } else {
                flags |= IOMAP_WRITE;
diff --combined fs/read_write.c
index 603794b207ebad39946e96bcbfff73332fc9a0a0,7f79b1fc490ecb0d12cc09e7fb18f87499358574..5a2ee488c5d2a3b35cb8cb941c652215cb96f7da
@@@ -331,7 -331,7 +331,7 @@@ COMPAT_SYSCALL_DEFINE3(lseek, unsigned 
  }
  #endif
  
 -#ifdef __ARCH_WANT_SYS_LLSEEK
 +#if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT)
  SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                unsigned long, offset_low, loff_t __user *, result,
                unsigned int, whence)
@@@ -1407,7 -1407,6 +1407,6 @@@ static ssize_t do_sendfile(int out_fd, 
                goto fput_in;
        if (!(out.file->f_mode & FMODE_WRITE))
                goto fput_out;
-       retval = -EINVAL;
        in_inode = file_inode(in.file);
        out_inode = file_inode(out.file);
        out_pos = out.file->f_pos;
@@@ -1818,8 -1817,8 +1817,8 @@@ int vfs_clone_file_prep_inodes(struct i
  }
  EXPORT_SYMBOL(vfs_clone_file_prep_inodes);
  
 -int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
 -              struct file *file_out, loff_t pos_out, u64 len)
 +int do_clone_file_range(struct file *file_in, loff_t pos_in,
 +                      struct file *file_out, loff_t pos_out, u64 len)
  {
        struct inode *inode_in = file_inode(file_in);
        struct inode *inode_out = file_inode(file_out);
  
        return ret;
  }
 +EXPORT_SYMBOL(do_clone_file_range);
 +
 +int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
 +                       struct file *file_out, loff_t pos_out, u64 len)
 +{
 +      int ret;
 +
 +      file_start_write(file_out);
 +      ret = do_clone_file_range(file_in, pos_in, file_out, pos_out, len);
 +      file_end_write(file_out);
 +
 +      return ret;
 +}
  EXPORT_SYMBOL(vfs_clone_file_range);
  
  /*
@@@ -1977,6 -1963,20 +1976,20 @@@ out_error
  }
  EXPORT_SYMBOL(vfs_dedupe_file_range_compare);
  
+ /* Check whether we are allowed to dedupe the destination file */
+ static bool allow_file_dedupe(struct file *file)
+ {
+       if (capable(CAP_SYS_ADMIN))
+               return true;
+       if (file->f_mode & FMODE_WRITE)
+               return true;
+       if (uid_eq(current_fsuid(), file_inode(file)->i_uid))
+               return true;
+       if (!inode_permission(file_inode(file), MAY_WRITE))
+               return true;
+       return false;
+ }
  int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
                              struct file *dst_file, loff_t dst_pos, u64 len)
  {
        if (ret < 0)
                goto out_drop_write;
  
-       ret = -EINVAL;
-       if (!(capable(CAP_SYS_ADMIN) || (dst_file->f_mode & FMODE_WRITE)))
+       ret = -EPERM;
+       if (!allow_file_dedupe(dst_file))
                goto out_drop_write;
  
        ret = -EXDEV;