Merge tag 'for-4.20-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 11 Nov 2018 22:54:38 +0000 (16:54 -0600)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 11 Nov 2018 22:54:38 +0000 (16:54 -0600)
Pull btrfs fixes from David Sterba:
 "Several fixes to recent release (4.19, fixes tagged for stable) and
  other fixes"

* tag 'for-4.20-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  Btrfs: fix missing delayed iputs on unmount
  Btrfs: fix data corruption due to cloning of eof block
  Btrfs: fix infinite loop on inode eviction after deduplication of eof block
  Btrfs: fix deadlock on tree root leaf when finding free extent
  btrfs: avoid link error with CONFIG_NO_AUTO_INLINE
  btrfs: tree-checker: Fix misleading group system information
  Btrfs: fix missing data checksums after a ranged fsync (msync)
  btrfs: fix pinned underflow after transaction aborted
  Btrfs: fix cur_offset in the error case for nocow

1  2 
fs/btrfs/ctree.h
fs/btrfs/inode.c
fs/btrfs/ioctl.c

diff --combined fs/btrfs/ctree.h
index 80953528572db52af07ceae9ec782b284ab29610,f7f955109d8b5344cd930ed245e27fcd652a9040..68f322f600a0677813867c5278b5aca9c23a6e8f
@@@ -3163,6 -3163,9 +3163,9 @@@ void btrfs_destroy_inode(struct inode *
  int btrfs_drop_inode(struct inode *inode);
  int __init btrfs_init_cachep(void);
  void __cold btrfs_destroy_cachep(void);
+ struct inode *btrfs_iget_path(struct super_block *s, struct btrfs_key *location,
+                             struct btrfs_root *root, int *new,
+                             struct btrfs_path *path);
  struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
                         struct btrfs_root *root, int *was_new);
  struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
@@@ -3201,6 -3204,9 +3204,6 @@@ void btrfs_get_block_group_info(struct 
                                struct btrfs_ioctl_space_info *space);
  void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
                               struct btrfs_ioctl_balance_args *bargs);
 -int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
 -                          struct file *dst_file, loff_t dst_loff,
 -                          u64 olen);
  
  /* file.c */
  int __init btrfs_auto_defrag_init(void);
@@@ -3230,9 -3236,8 +3233,9 @@@ int btrfs_dirty_pages(struct inode *ino
                      size_t num_pages, loff_t pos, size_t write_bytes,
                      struct extent_state **cached);
  int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
 -int btrfs_clone_file_range(struct file *file_in, loff_t pos_in,
 -                         struct file *file_out, loff_t pos_out, u64 len);
 +loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in,
 +                            struct file *file_out, loff_t pos_out,
 +                            loff_t len, unsigned int remap_flags);
  
  /* tree-defrag.c */
  int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
diff --combined fs/btrfs/inode.c
index d3df5b52278cea06c05384ef7bf63aaed6b5404f,e71daadd2f75a00ea54f96489fecf7c072f6bbb3..9ea4c6f0352f06e828a400890c50122c7ec33ee5
@@@ -1531,12 -1531,11 +1531,11 @@@ out_check
        }
        btrfs_release_path(path);
  
-       if (cur_offset <= end && cow_start == (u64)-1) {
+       if (cur_offset <= end && cow_start == (u64)-1)
                cow_start = cur_offset;
-               cur_offset = end;
-       }
  
        if (cow_start != (u64)-1) {
+               cur_offset = end;
                ret = cow_file_range(inode, locked_page, cow_start, end, end,
                                     page_started, nr_written, 1, NULL);
                if (ret)
@@@ -3570,10 -3569,11 +3569,11 @@@ static noinline int acls_after_inode_it
  /*
   * read an inode from the btree into the in-memory inode
   */
- static int btrfs_read_locked_inode(struct inode *inode)
+ static int btrfs_read_locked_inode(struct inode *inode,
+                                  struct btrfs_path *in_path)
  {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       struct btrfs_path *path;
+       struct btrfs_path *path = in_path;
        struct extent_buffer *leaf;
        struct btrfs_inode_item *inode_item;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        if (!ret)
                filled = true;
  
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
+       if (!path) {
+               path = btrfs_alloc_path();
+               if (!path)
+                       return -ENOMEM;
+       }
  
        memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
  
        ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
        if (ret) {
-               btrfs_free_path(path);
+               if (path != in_path)
+                       btrfs_free_path(path);
                return ret;
        }
  
@@@ -3722,7 -3725,8 +3725,8 @@@ cache_acl
                                  btrfs_ino(BTRFS_I(inode)),
                                  root->root_key.objectid, ret);
        }
-       btrfs_free_path(path);
+       if (path != in_path)
+               btrfs_free_path(path);
  
        if (!maybe_acls)
                cache_no_acl(inode);
@@@ -5644,8 -5648,9 +5648,9 @@@ static struct inode *btrfs_iget_locked(
  /* Get an inode object given its location and corresponding root.
   * Returns in *is_new if the inode was read from disk
   */
- struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
-                        struct btrfs_root *root, int *new)
+ struct inode *btrfs_iget_path(struct super_block *s, struct btrfs_key *location,
+                             struct btrfs_root *root, int *new,
+                             struct btrfs_path *path)
  {
        struct inode *inode;
  
        if (inode->i_state & I_NEW) {
                int ret;
  
-               ret = btrfs_read_locked_inode(inode);
+               ret = btrfs_read_locked_inode(inode, path);
                if (!ret) {
                        inode_tree_add(inode);
                        unlock_new_inode(inode);
        return inode;
  }
  
+ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
+                        struct btrfs_root *root, int *new)
+ {
+       return btrfs_iget_path(s, location, root, new, NULL);
+ }
  static struct inode *new_simple_dir(struct super_block *s,
                                    struct btrfs_key *key,
                                    struct btrfs_root *root)
@@@ -5775,10 -5786,16 +5786,10 @@@ static int btrfs_dentry_delete(const st
  static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
                                   unsigned int flags)
  {
 -      struct inode *inode;
 -
 -      inode = btrfs_lookup_dentry(dir, dentry);
 -      if (IS_ERR(inode)) {
 -              if (PTR_ERR(inode) == -ENOENT)
 -                      inode = NULL;
 -              else
 -                      return ERR_CAST(inode);
 -      }
 +      struct inode *inode = btrfs_lookup_dentry(dir, dentry);
  
 +      if (inode == ERR_PTR(-ENOENT))
 +              inode = NULL;
        return d_splice_alias(inode, dentry);
  }
  
diff --combined fs/btrfs/ioctl.c
index 3ca6943827ef88e536b2d6c924e7664a3ab835e7,95f9625dccc4a2d7871f25d82a3f09fe345d9812..802a628e9f7d7fe629a76e8d108b75c04ed4246e
@@@ -3488,6 -3488,8 +3488,8 @@@ static int btrfs_extent_same_range(stru
                        const u64 sz = BTRFS_I(src)->root->fs_info->sectorsize;
  
                        len = round_down(i_size_read(src), sz) - loff;
+                       if (len == 0)
+                               return 0;
                        olen = len;
                }
        }
@@@ -3629,6 -3631,26 +3631,6 @@@ out_unlock
        return ret;
  }
  
 -int btrfs_dedupe_file_range(struct file *src_file, loff_t src_loff,
 -                          struct file *dst_file, loff_t dst_loff,
 -                          u64 olen)
 -{
 -      struct inode *src = file_inode(src_file);
 -      struct inode *dst = file_inode(dst_file);
 -      u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
 -
 -      if (WARN_ON_ONCE(bs < PAGE_SIZE)) {
 -              /*
 -               * Btrfs does not support blocksize < page_size. As a
 -               * result, btrfs_cmp_data() won't correctly handle
 -               * this situation without an update.
 -               */
 -              return -EINVAL;
 -      }
 -
 -      return btrfs_extent_same(src, src_loff, olen, dst, dst_loff);
 -}
 -
  static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
                                     struct inode *inode,
                                     u64 endoff,
@@@ -4257,9 -4279,17 +4259,17 @@@ static noinline int btrfs_clone_files(s
                goto out_unlock;
        if (len == 0)
                olen = len = src->i_size - off;
-       /* if we extend to eof, continue to block boundary */
-       if (off + len == src->i_size)
+       /*
+        * If we extend to eof, continue to block boundary if and only if the
+        * destination end offset matches the destination file's size, otherwise
+        * we would be corrupting data by placing the eof block into the middle
+        * of a file.
+        */
+       if (off + len == src->i_size) {
+               if (!IS_ALIGNED(len, bs) && destoff + len < inode->i_size)
+                       goto out_unlock;
                len = ALIGN(src->i_size, bs) - off;
+       }
  
        if (len == 0) {
                ret = 0;
@@@ -4330,34 -4360,10 +4340,34 @@@ out_unlock
        return ret;
  }
  
 -int btrfs_clone_file_range(struct file *src_file, loff_t off,
 -              struct file *dst_file, loff_t destoff, u64 len)
 +loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
 +              struct file *dst_file, loff_t destoff, loff_t len,
 +              unsigned int remap_flags)
  {
 -      return btrfs_clone_files(dst_file, src_file, off, len, destoff);
 +      int ret;
 +
 +      if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
 +              return -EINVAL;
 +
 +      if (remap_flags & REMAP_FILE_DEDUP) {
 +              struct inode *src = file_inode(src_file);
 +              struct inode *dst = file_inode(dst_file);
 +              u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
 +
 +              if (WARN_ON_ONCE(bs < PAGE_SIZE)) {
 +                      /*
 +                       * Btrfs does not support blocksize < page_size. As a
 +                       * result, btrfs_cmp_data() won't correctly handle
 +                       * this situation without an update.
 +                       */
 +                      return -EINVAL;
 +              }
 +
 +              ret = btrfs_extent_same(src, off, len, dst, destoff);
 +      } else {
 +              ret = btrfs_clone_files(dst_file, src_file, off, len, destoff);
 +      }
 +      return ret < 0 ? ret : len;
  }
  
  static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)