Merge branch 'for-linus-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mason...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Jan 2016 19:49:21 +0000 (11:49 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Jan 2016 19:49:21 +0000 (11:49 -0800)
Pull more btrfs updates from Chris Mason:
 "These are mostly fixes that we've been testing, but also we grabbed
  and tested a few small cleanups that had been on the list for a while.

  Zhao Lei's patchset also fixes some early ENOSPC buglets"

* 'for-linus-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (21 commits)
  btrfs: raid56: Use raid_write_end_io for scrub
  btrfs: Remove unnecessary ClearPageUptodate for raid56
  btrfs: use rbio->nr_pages to reduce calculation
  btrfs: Use unified stripe_page's index calculation
  btrfs: Fix calculation of rbio->dbitmap's size calculation
  btrfs: Fix no_space in write and rm loop
  btrfs: merge functions for wait snapshot creation
  btrfs: delete unused argument in btrfs_copy_from_user
  btrfs: Use direct way to determine raid56 write/recover mode
  btrfs: Small cleanup for get index_srcdev loop
  btrfs: Enhance chunk validation check
  btrfs: Enhance super validation check
  Btrfs: fix deadlock running delayed iputs at transaction commit time
  Btrfs: fix typo in log message when starting a balance
  btrfs: remove duplicate const specifier
  btrfs: initialize the seq counter in struct btrfs_device
  Btrfs: clean up an error code in btrfs_init_space_info()
  btrfs: fix iterator with update error in backref.c
  Btrfs: fix output of compression message in btrfs_parse_options()
  Btrfs: Initialize btrfs_root->highest_objectid when loading tree root and subvolume roots
  ...

1  2 
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/super.c

diff --combined fs/btrfs/ctree.h
index 97ad9bbeb35d24ec0ad228aa6f040b61bffb33a5,a9496644f47d3e8b89fbefc5de4faf041f838120..bfe4a337fb4d13a058446265b7baf4a1437aa602
@@@ -1614,7 -1614,7 +1614,7 @@@ struct btrfs_fs_info 
  
        spinlock_t delayed_iput_lock;
        struct list_head delayed_iputs;
-       struct rw_semaphore delayed_iput_sem;
+       struct mutex cleaner_delayed_iput_mutex;
  
        /* this protects tree_mod_seq_list */
        spinlock_t tree_mod_seq_lock;
@@@ -3641,6 -3641,7 +3641,7 @@@ int btrfs_delayed_refs_qgroup_accountin
  int __get_raid_index(u64 flags);
  int btrfs_start_write_no_snapshoting(struct btrfs_root *root);
  void btrfs_end_write_no_snapshoting(struct btrfs_root *root);
+ void btrfs_wait_for_snapshot_creation(struct btrfs_root *root);
  void check_system_chunk(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root,
                        const u64 type);
@@@ -4098,8 -4099,7 +4099,8 @@@ void btrfs_get_block_group_info(struct 
                                struct btrfs_ioctl_space_info *space);
  void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
                               struct btrfs_ioctl_balance_args *bargs);
 -
 +ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
 +                         struct file *dst_file, u64 dst_loff);
  
  /* file.c */
  int btrfs_auto_defrag_init(void);
@@@ -4130,11 -4130,6 +4131,11 @@@ int btrfs_dirty_pages(struct btrfs_roo
                      loff_t pos, size_t write_bytes,
                      struct extent_state **cached);
  int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
 +ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
 +                            struct file *file_out, loff_t pos_out,
 +                            size_t len, unsigned int flags);
 +int btrfs_clone_file_range(struct file *file_in, loff_t pos_in,
 +                         struct file *file_out, loff_t pos_out, u64 len);
  
  /* tree-defrag.c */
  int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
diff --combined fs/btrfs/disk-io.c
index e99ccd6ffb2c14f58bf38f548e202f0e0f86e9ea,26ef141520936bdbcb41110e2fa572fccfbac85c..dd08e29f51177d27859c12f0d173224a24a1f4a9
  #include <asm/cpufeature.h>
  #endif
  
+ #define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\
+                                BTRFS_HEADER_FLAG_RELOC |\
+                                BTRFS_SUPER_FLAG_ERROR |\
+                                BTRFS_SUPER_FLAG_SEEDING |\
+                                BTRFS_SUPER_FLAG_METADUMP)
  static const struct extent_io_ops btree_extent_io_ops;
  static void end_workqueue_fn(struct btrfs_work *work);
  static void free_fs_root(struct btrfs_root *root);
@@@ -924,7 -930,7 +930,7 @@@ static int check_async_write(struct ino
        if (bio_flags & EXTENT_BIO_TREE_LOG)
                return 0;
  #ifdef CONFIG_X86
 -      if (cpu_has_xmm4_2)
 +      if (static_cpu_has_safe(X86_FEATURE_XMM4_2))
                return 0;
  #endif
        return 1;
@@@ -1583,8 -1589,23 +1589,23 @@@ int btrfs_init_fs_root(struct btrfs_roo
        ret = get_anon_bdev(&root->anon_dev);
        if (ret)
                goto free_writers;
+       mutex_lock(&root->objectid_mutex);
+       ret = btrfs_find_highest_objectid(root,
+                                       &root->highest_objectid);
+       if (ret) {
+               mutex_unlock(&root->objectid_mutex);
+               goto free_root_dev;
+       }
+       ASSERT(root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID);
+       mutex_unlock(&root->objectid_mutex);
        return 0;
  
+ free_root_dev:
+       free_anon_bdev(root->anon_dev);
  free_writers:
        btrfs_free_subvolume_writers(root->subv_writers);
  fail:
@@@ -1786,7 -1807,10 +1807,10 @@@ static int cleaner_kthread(void *arg
                        goto sleep;
                }
  
+               mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex);
                btrfs_run_delayed_iputs(root);
+               mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex);
                again = btrfs_clean_one_deleted_snapshot(root);
                mutex_unlock(&root->fs_info->cleaner_mutex);
  
@@@ -2556,8 -2580,8 +2580,8 @@@ int open_ctree(struct super_block *sb
        mutex_init(&fs_info->delete_unused_bgs_mutex);
        mutex_init(&fs_info->reloc_mutex);
        mutex_init(&fs_info->delalloc_root_mutex);
+       mutex_init(&fs_info->cleaner_delayed_iput_mutex);
        seqlock_init(&fs_info->profiles_lock);
-       init_rwsem(&fs_info->delayed_iput_sem);
  
        INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
        INIT_LIST_HEAD(&fs_info->space_info);
                goto fail_alloc;
        }
  
-       /*
-        * Leafsize and nodesize were always equal, this is only a sanity check.
-        */
-       if (le32_to_cpu(disk_super->__unused_leafsize) !=
-           btrfs_super_nodesize(disk_super)) {
-               printk(KERN_ERR "BTRFS: couldn't mount because metadata "
-                      "blocksizes don't match.  node %d leaf %d\n",
-                      btrfs_super_nodesize(disk_super),
-                      le32_to_cpu(disk_super->__unused_leafsize));
-               err = -EINVAL;
-               goto fail_alloc;
-       }
-       if (btrfs_super_nodesize(disk_super) > BTRFS_MAX_METADATA_BLOCKSIZE) {
-               printk(KERN_ERR "BTRFS: couldn't mount because metadata "
-                      "blocksize (%d) was too large\n",
-                      btrfs_super_nodesize(disk_super));
-               err = -EINVAL;
-               goto fail_alloc;
-       }
        features = btrfs_super_incompat_flags(disk_super);
        features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
        if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_LZO)
        sb->s_blocksize = sectorsize;
        sb->s_blocksize_bits = blksize_bits(sectorsize);
  
-       if (btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
-               printk(KERN_ERR "BTRFS: valid FS not found on %s\n", sb->s_id);
-               goto fail_sb_buffer;
-       }
-       if (sectorsize != PAGE_SIZE) {
-               printk(KERN_ERR "BTRFS: incompatible sector size (%lu) "
-                      "found on %s\n", (unsigned long)sectorsize, sb->s_id);
-               goto fail_sb_buffer;
-       }
        mutex_lock(&fs_info->chunk_mutex);
        ret = btrfs_read_sys_array(tree_root);
        mutex_unlock(&fs_info->chunk_mutex);
@@@ -2915,6 -2908,18 +2908,18 @@@ retry_root_backup
        tree_root->commit_root = btrfs_root_node(tree_root);
        btrfs_set_root_refs(&tree_root->root_item, 1);
  
+       mutex_lock(&tree_root->objectid_mutex);
+       ret = btrfs_find_highest_objectid(tree_root,
+                                       &tree_root->highest_objectid);
+       if (ret) {
+               mutex_unlock(&tree_root->objectid_mutex);
+               goto recovery_tree_root;
+       }
+       ASSERT(tree_root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID);
+       mutex_unlock(&tree_root->objectid_mutex);
        ret = btrfs_read_roots(fs_info, tree_root);
        if (ret)
                goto recovery_tree_root;
@@@ -4018,8 -4023,17 +4023,17 @@@ static int btrfs_check_super_valid(stru
                              int read_only)
  {
        struct btrfs_super_block *sb = fs_info->super_copy;
+       u64 nodesize = btrfs_super_nodesize(sb);
+       u64 sectorsize = btrfs_super_sectorsize(sb);
        int ret = 0;
  
+       if (btrfs_super_magic(sb) != BTRFS_MAGIC) {
+               printk(KERN_ERR "BTRFS: no valid FS found\n");
+               ret = -EINVAL;
+       }
+       if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP)
+               printk(KERN_WARNING "BTRFS: unrecognized super flag: %llu\n",
+                               btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP);
        if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) {
                printk(KERN_ERR "BTRFS: tree_root level too big: %d >= %d\n",
                                btrfs_super_root_level(sb), BTRFS_MAX_LEVEL);
        }
  
        /*
-        * The common minimum, we don't know if we can trust the nodesize/sectorsize
-        * items yet, they'll be verified later. Issue just a warning.
+        * Check sectorsize and nodesize first, other check will need it.
+        * Check all possible sectorsize(4K, 8K, 16K, 32K, 64K) here.
         */
-       if (!IS_ALIGNED(btrfs_super_root(sb), 4096))
+       if (!is_power_of_2(sectorsize) || sectorsize < 4096 ||
+           sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) {
+               printk(KERN_ERR "BTRFS: invalid sectorsize %llu\n", sectorsize);
+               ret = -EINVAL;
+       }
+       /* Only PAGE SIZE is supported yet */
+       if (sectorsize != PAGE_CACHE_SIZE) {
+               printk(KERN_ERR "BTRFS: sectorsize %llu not supported yet, only support %lu\n",
+                               sectorsize, PAGE_CACHE_SIZE);
+               ret = -EINVAL;
+       }
+       if (!is_power_of_2(nodesize) || nodesize < sectorsize ||
+           nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) {
+               printk(KERN_ERR "BTRFS: invalid nodesize %llu\n", nodesize);
+               ret = -EINVAL;
+       }
+       if (nodesize != le32_to_cpu(sb->__unused_leafsize)) {
+               printk(KERN_ERR "BTRFS: invalid leafsize %u, should be %llu\n",
+                               le32_to_cpu(sb->__unused_leafsize),
+                               nodesize);
+               ret = -EINVAL;
+       }
+       /* Root alignment check */
+       if (!IS_ALIGNED(btrfs_super_root(sb), sectorsize)) {
                printk(KERN_WARNING "BTRFS: tree_root block unaligned: %llu\n",
                                btrfs_super_root(sb));
-       if (!IS_ALIGNED(btrfs_super_chunk_root(sb), 4096))
+               ret = -EINVAL;
+       }
+       if (!IS_ALIGNED(btrfs_super_chunk_root(sb), sectorsize)) {
                printk(KERN_WARNING "BTRFS: chunk_root block unaligned: %llu\n",
                                btrfs_super_chunk_root(sb));
-       if (!IS_ALIGNED(btrfs_super_log_root(sb), 4096))
-               printk(KERN_WARNING "BTRFS: log_root block unaligned: %llu\n",
-                               btrfs_super_log_root(sb));
-       /*
-        * Check the lower bound, the alignment and other constraints are
-        * checked later.
-        */
-       if (btrfs_super_nodesize(sb) < 4096) {
-               printk(KERN_ERR "BTRFS: nodesize too small: %u < 4096\n",
-                               btrfs_super_nodesize(sb));
                ret = -EINVAL;
        }
-       if (btrfs_super_sectorsize(sb) < 4096) {
-               printk(KERN_ERR "BTRFS: sectorsize too small: %u < 4096\n",
-                               btrfs_super_sectorsize(sb));
+       if (!IS_ALIGNED(btrfs_super_log_root(sb), sectorsize)) {
+               printk(KERN_WARNING "BTRFS: log_root block unaligned: %llu\n",
+                               btrfs_super_log_root(sb));
                ret = -EINVAL;
        }
  
diff --combined fs/btrfs/file.c
index 83d7859d76199d96ec882c35c87dea98526d229e,af782fdd4fcab60acf638ebec752dd205d5d998c..9f5cc1e8e126cc65c53093a0e0740d0ff0fd5f57
@@@ -406,8 -406,7 +406,7 @@@ int btrfs_run_defrag_inodes(struct btrf
  /* simple helper to fault in pages and copy.  This should go away
   * and be replaced with calls into generic code.
   */
- static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
-                                        size_t write_bytes,
+ static noinline int btrfs_copy_from_user(loff_t pos, size_t write_bytes,
                                         struct page **prepared_pages,
                                         struct iov_iter *i)
  {
@@@ -1588,8 -1587,7 +1587,7 @@@ again
                        ret = 0;
                }
  
-               copied = btrfs_copy_from_user(pos, num_pages,
-                                          write_bytes, pages, i);
+               copied = btrfs_copy_from_user(pos, write_bytes, pages, i);
  
                /*
                 * if we have trouble faulting in the pages, fall
@@@ -2934,9 -2932,6 +2932,9 @@@ const struct file_operations btrfs_file
  #ifdef CONFIG_COMPAT
        .compat_ioctl   = btrfs_ioctl,
  #endif
 +      .copy_file_range = btrfs_copy_file_range,
 +      .clone_file_range = btrfs_clone_file_range,
 +      .dedupe_file_range = btrfs_dedupe_file_range,
  };
  
  void btrfs_auto_defrag_exit(void)
diff --combined fs/btrfs/inode.c
index 24783010768680bea28f4f0e5e9aaa2c6a62a41c,b8bb7591ff9f4445f7988b7405e63c76a1b733b3..1b79dc9b12e4fb78fcc4005511ab73be05a4294e
@@@ -3134,7 -3134,6 +3134,6 @@@ void btrfs_run_delayed_iputs(struct btr
  {
        struct btrfs_fs_info *fs_info = root->fs_info;
  
-       down_read(&fs_info->delayed_iput_sem);
        spin_lock(&fs_info->delayed_iput_lock);
        while (!list_empty(&fs_info->delayed_iputs)) {
                struct btrfs_inode *inode;
                spin_lock(&fs_info->delayed_iput_lock);
        }
        spin_unlock(&fs_info->delayed_iput_lock);
-       up_read(&root->fs_info->delayed_iput_sem);
  }
  
  /*
@@@ -3548,10 -3546,10 +3546,10 @@@ static noinline int acls_after_inode_it
        int scanned = 0;
  
        if (!xattr_access) {
 -              xattr_access = btrfs_name_hash(POSIX_ACL_XATTR_ACCESS,
 -                                      strlen(POSIX_ACL_XATTR_ACCESS));
 -              xattr_default = btrfs_name_hash(POSIX_ACL_XATTR_DEFAULT,
 -                                      strlen(POSIX_ACL_XATTR_DEFAULT));
 +              xattr_access = btrfs_name_hash(XATTR_NAME_POSIX_ACL_ACCESS,
 +                                      strlen(XATTR_NAME_POSIX_ACL_ACCESS));
 +              xattr_default = btrfs_name_hash(XATTR_NAME_POSIX_ACL_DEFAULT,
 +                                      strlen(XATTR_NAME_POSIX_ACL_DEFAULT));
        }
  
        slot++;
@@@ -3772,7 -3770,6 +3770,7 @@@ cache_acl
                break;
        case S_IFLNK:
                inode->i_op = &btrfs_symlink_inode_operations;
 +              inode_nohighmem(inode);
                inode->i_mapping->a_ops = &btrfs_symlink_aops;
                break;
        default:
@@@ -4874,26 -4871,6 +4872,6 @@@ next
        return err;
  }
  
- static int wait_snapshoting_atomic_t(atomic_t *a)
- {
-       schedule();
-       return 0;
- }
- static void wait_for_snapshot_creation(struct btrfs_root *root)
- {
-       while (true) {
-               int ret;
-               ret = btrfs_start_write_no_snapshoting(root);
-               if (ret)
-                       break;
-               wait_on_atomic_t(&root->will_be_snapshoted,
-                                wait_snapshoting_atomic_t,
-                                TASK_UNINTERRUPTIBLE);
-       }
- }
  static int btrfs_setsize(struct inode *inode, struct iattr *attr)
  {
        struct btrfs_root *root = BTRFS_I(inode)->root;
                 * truncation, it must capture all writes that happened before
                 * this truncation.
                 */
-               wait_for_snapshot_creation(root);
+               btrfs_wait_for_snapshot_creation(root);
                ret = btrfs_cont_expand(inode, oldsize, newsize);
                if (ret) {
                        btrfs_end_write_no_snapshoting(root);
@@@ -9194,8 -9171,7 +9172,8 @@@ int btrfs_init_cachep(void
  {
        btrfs_inode_cachep = kmem_cache_create("btrfs_inode",
                        sizeof(struct btrfs_inode), 0,
 -                      SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, init_once);
 +                      SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_ACCOUNT,
 +                      init_once);
        if (!btrfs_inode_cachep)
                goto fail;
  
@@@ -9726,7 -9702,6 +9704,7 @@@ static int btrfs_symlink(struct inode *
        btrfs_free_path(path);
  
        inode->i_op = &btrfs_symlink_inode_operations;
 +      inode_nohighmem(inode);
        inode->i_mapping->a_ops = &btrfs_symlink_aops;
        inode_set_bytes(inode, name_len);
        btrfs_i_size_write(inode, name_len);
@@@ -10023,7 -9998,7 +10001,7 @@@ static const struct inode_operations bt
        .setattr        = btrfs_setattr,
        .mknod          = btrfs_mknod,
        .setxattr       = btrfs_setxattr,
 -      .getxattr       = btrfs_getxattr,
 +      .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
@@@ -10100,7 -10075,7 +10078,7 @@@ static const struct inode_operations bt
        .getattr        = btrfs_getattr,
        .setattr        = btrfs_setattr,
        .setxattr       = btrfs_setxattr,
 -      .getxattr       = btrfs_getxattr,
 +      .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
@@@ -10114,7 -10089,7 +10092,7 @@@ static const struct inode_operations bt
        .setattr        = btrfs_setattr,
        .permission     = btrfs_permission,
        .setxattr       = btrfs_setxattr,
 -      .getxattr       = btrfs_getxattr,
 +      .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .get_acl        = btrfs_get_acl,
  };
  static const struct inode_operations btrfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
 -      .follow_link    = page_follow_link_light,
 -      .put_link       = page_put_link,
 +      .get_link       = page_get_link,
        .getattr        = btrfs_getattr,
        .setattr        = btrfs_setattr,
        .permission     = btrfs_permission,
        .setxattr       = btrfs_setxattr,
 -      .getxattr       = btrfs_getxattr,
 +      .getxattr       = generic_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .update_time    = btrfs_update_time,
diff --combined fs/btrfs/ioctl.c
index 2a47a3148ec80df57150e3f5aa7d321abb8d1ccd,83c9ad3f2621ea74a4b7764fdac29c81ec738744..9028737ee9b506fa734382aa6d3c434c072d65b5
@@@ -568,6 -568,10 +568,10 @@@ static noinline int create_subvol(struc
                goto fail;
        }
  
+       mutex_lock(&new_root->objectid_mutex);
+       new_root->highest_objectid = new_dirid;
+       mutex_unlock(&new_root->objectid_mutex);
        /*
         * insert the directory item
         */
@@@ -2970,7 -2974,7 +2974,7 @@@ static int btrfs_cmp_data(struct inode 
                flush_dcache_page(dst_page);
  
                if (memcmp(addr, dst_addr, cmp_len))
 -                      ret = BTRFS_SAME_DATA_DIFFERS;
 +                      ret = -EBADE;
  
                kunmap_atomic(addr);
                kunmap_atomic(dst_addr);
@@@ -3106,16 -3110,53 +3110,16 @@@ out_unlock
  
  #define BTRFS_MAX_DEDUPE_LEN  SZ_16M
  
 -static long btrfs_ioctl_file_extent_same(struct file *file,
 -                      struct btrfs_ioctl_same_args __user *argp)
 +ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
 +                              struct file *dst_file, u64 dst_loff)
  {
 -      struct btrfs_ioctl_same_args *same = NULL;
 -      struct btrfs_ioctl_same_extent_info *info;
 -      struct inode *src = file_inode(file);
 -      u64 off;
 -      u64 len;
 -      int i;
 -      int ret;
 -      unsigned long size;
 +      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;
 -      bool is_admin = capable(CAP_SYS_ADMIN);
 -      u16 count;
 -
 -      if (!(file->f_mode & FMODE_READ))
 -              return -EINVAL;
 -
 -      ret = mnt_want_write_file(file);
 -      if (ret)
 -              return ret;
 -
 -      if (get_user(count, &argp->dest_count)) {
 -              ret = -EFAULT;
 -              goto out;
 -      }
 -
 -      size = offsetof(struct btrfs_ioctl_same_args __user, info[count]);
 -
 -      same = memdup_user(argp, size);
 -
 -      if (IS_ERR(same)) {
 -              ret = PTR_ERR(same);
 -              same = NULL;
 -              goto out;
 -      }
 +      ssize_t res;
  
 -      off = same->logical_offset;
 -      len = same->length;
 -
 -      /*
 -       * Limit the total length we will dedupe for each operation.
 -       * This is intended to bound the total time spent in this
 -       * ioctl to something sane.
 -       */
 -      if (len > BTRFS_MAX_DEDUPE_LEN)
 -              len = BTRFS_MAX_DEDUPE_LEN;
 +      if (olen > BTRFS_MAX_DEDUPE_LEN)
 +              olen = BTRFS_MAX_DEDUPE_LEN;
  
        if (WARN_ON_ONCE(bs < PAGE_CACHE_SIZE)) {
                /*
                 * result, btrfs_cmp_data() won't correctly handle
                 * this situation without an update.
                 */
 -              ret = -EINVAL;
 -              goto out;
 -      }
 -
 -      ret = -EISDIR;
 -      if (S_ISDIR(src->i_mode))
 -              goto out;
 -
 -      ret = -EACCES;
 -      if (!S_ISREG(src->i_mode))
 -              goto out;
 -
 -      /* pre-format output fields to sane values */
 -      for (i = 0; i < count; i++) {
 -              same->info[i].bytes_deduped = 0ULL;
 -              same->info[i].status = 0;
 -      }
 -
 -      for (i = 0, info = same->info; i < count; i++, info++) {
 -              struct inode *dst;
 -              struct fd dst_file = fdget(info->fd);
 -              if (!dst_file.file) {
 -                      info->status = -EBADF;
 -                      continue;
 -              }
 -              dst = file_inode(dst_file.file);
 -
 -              if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) {
 -                      info->status = -EINVAL;
 -              } else if (file->f_path.mnt != dst_file.file->f_path.mnt) {
 -                      info->status = -EXDEV;
 -              } else if (S_ISDIR(dst->i_mode)) {
 -                      info->status = -EISDIR;
 -              } else if (!S_ISREG(dst->i_mode)) {
 -                      info->status = -EACCES;
 -              } else {
 -                      info->status = btrfs_extent_same(src, off, len, dst,
 -                                                      info->logical_offset);
 -                      if (info->status == 0)
 -                              info->bytes_deduped += len;
 -              }
 -              fdput(dst_file);
 +              return -EINVAL;
        }
  
 -      ret = copy_to_user(argp, same, size);
 -      if (ret)
 -              ret = -EFAULT;
 -
 -out:
 -      mnt_drop_write_file(file);
 -      kfree(same);
 -      return ret;
 +      res = btrfs_extent_same(src, loff, olen, dst, dst_loff);
 +      if (res)
 +              return res;
 +      return olen;
  }
  
  static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
        return ret;
  }
  
 -static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 -                                     u64 off, u64 olen, u64 destoff)
 +static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
 +                                      u64 off, u64 olen, u64 destoff)
  {
        struct inode *inode = file_inode(file);
 +      struct inode *src = file_inode(file_src);
        struct btrfs_root *root = BTRFS_I(inode)->root;
 -      struct fd src_file;
 -      struct inode *src;
        int ret;
        u64 len = olen;
        u64 bs = root->fs_info->sb->s_blocksize;
 -      int same_inode = 0;
 +      int same_inode = src == inode;
  
        /*
         * TODO:
         *   be either compressed or non-compressed.
         */
  
 -      /* the destination must be opened for writing */
 -      if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
 -              return -EINVAL;
 -
        if (btrfs_root_readonly(root))
                return -EROFS;
  
 -      ret = mnt_want_write_file(file);
 -      if (ret)
 -              return ret;
 -
 -      src_file = fdget(srcfd);
 -      if (!src_file.file) {
 -              ret = -EBADF;
 -              goto out_drop_write;
 -      }
 -
 -      ret = -EXDEV;
 -      if (src_file.file->f_path.mnt != file->f_path.mnt)
 -              goto out_fput;
 -
 -      src = file_inode(src_file.file);
 -
 -      ret = -EINVAL;
 -      if (src == inode)
 -              same_inode = 1;
 -
 -      /* the src must be open for reading */
 -      if (!(src_file.file->f_mode & FMODE_READ))
 -              goto out_fput;
 +      if (file_src->f_path.mnt != file->f_path.mnt ||
 +          src->i_sb != inode->i_sb)
 +              return -EXDEV;
  
        /* don't make the dst file partly checksummed */
        if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
            (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
 -              goto out_fput;
 +              return -EINVAL;
  
 -      ret = -EISDIR;
        if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
 -              goto out_fput;
 -
 -      ret = -EXDEV;
 -      if (src->i_sb != inode->i_sb)
 -              goto out_fput;
 +              return -EISDIR;
  
        if (!same_inode) {
                btrfs_double_inode_lock(src, inode);
@@@ -3817,25 -3933,21 +3821,25 @@@ out_unlock
                btrfs_double_inode_unlock(src, inode);
        else
                mutex_unlock(&src->i_mutex);
 -out_fput:
 -      fdput(src_file);
 -out_drop_write:
 -      mnt_drop_write_file(file);
        return ret;
  }
  
 -static long btrfs_ioctl_clone_range(struct file *file, void __user *argp)
 +ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
 +                            struct file *file_out, loff_t pos_out,
 +                            size_t len, unsigned int flags)
  {
 -      struct btrfs_ioctl_clone_range_args args;
 +      ssize_t ret;
  
 -      if (copy_from_user(&args, argp, sizeof(args)))
 -              return -EFAULT;
 -      return btrfs_ioctl_clone(file, args.src_fd, args.src_offset,
 -                               args.src_length, args.dest_offset);
 +      ret = btrfs_clone_files(file_out, file_in, pos_in, len, pos_out);
 +      if (ret == 0)
 +              ret = len;
 +      return ret;
 +}
 +
 +int btrfs_clone_file_range(struct file *src_file, loff_t off,
 +              struct file *dst_file, loff_t destoff, u64 len)
 +{
 +      return btrfs_clone_files(dst_file, src_file, off, len, destoff);
  }
  
  /*
@@@ -5385,6 -5497,10 +5389,6 @@@ long btrfs_ioctl(struct file *file, uns
                return btrfs_ioctl_dev_info(root, argp);
        case BTRFS_IOC_BALANCE:
                return btrfs_ioctl_balance(file, NULL);
 -      case BTRFS_IOC_CLONE:
 -              return btrfs_ioctl_clone(file, arg, 0, 0, 0);
 -      case BTRFS_IOC_CLONE_RANGE:
 -              return btrfs_ioctl_clone_range(file, argp);
        case BTRFS_IOC_TRANS_START:
                return btrfs_ioctl_trans_start(file);
        case BTRFS_IOC_TRANS_END:
                return btrfs_ioctl_get_fslabel(file, argp);
        case BTRFS_IOC_SET_FSLABEL:
                return btrfs_ioctl_set_fslabel(file, argp);
 -      case BTRFS_IOC_FILE_EXTENT_SAME:
 -              return btrfs_ioctl_file_extent_same(file, argp);
        case BTRFS_IOC_GET_SUPPORTED_FEATURES:
                return btrfs_ioctl_get_supported_features(file, argp);
        case BTRFS_IOC_GET_FEATURES:
diff --combined fs/btrfs/super.c
index 9b9eab6d048e93d32963b0c66a6d9ab6c022ee63,a8e049ae933dc0eea7bba35f7a2d598029a4f94a..d41e09fe8e38d77674862c7fe61f610a81d1159d
@@@ -383,6 -383,9 +383,9 @@@ int btrfs_parse_options(struct btrfs_ro
        int ret = 0;
        char *compress_type;
        bool compress_force = false;
+       enum btrfs_compression_type saved_compress_type;
+       bool saved_compress_force;
+       int no_compress = 0;
  
        cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy);
        if (btrfs_fs_compat_ro(root->fs_info, FREE_SPACE_TREE))
                        /* Fallthrough */
                case Opt_compress:
                case Opt_compress_type:
+                       saved_compress_type = btrfs_test_opt(root, COMPRESS) ?
+                               info->compress_type : BTRFS_COMPRESS_NONE;
+                       saved_compress_force =
+                               btrfs_test_opt(root, FORCE_COMPRESS);
                        if (token == Opt_compress ||
                            token == Opt_compress_force ||
                            strcmp(args[0].from, "zlib") == 0) {
                                btrfs_set_opt(info->mount_opt, COMPRESS);
                                btrfs_clear_opt(info->mount_opt, NODATACOW);
                                btrfs_clear_opt(info->mount_opt, NODATASUM);
+                               no_compress = 0;
                        } else if (strcmp(args[0].from, "lzo") == 0) {
                                compress_type = "lzo";
                                info->compress_type = BTRFS_COMPRESS_LZO;
                                btrfs_clear_opt(info->mount_opt, NODATACOW);
                                btrfs_clear_opt(info->mount_opt, NODATASUM);
                                btrfs_set_fs_incompat(info, COMPRESS_LZO);
+                               no_compress = 0;
                        } else if (strncmp(args[0].from, "no", 2) == 0) {
                                compress_type = "no";
                                btrfs_clear_opt(info->mount_opt, COMPRESS);
                                btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
                                compress_force = false;
+                               no_compress++;
                        } else {
                                ret = -EINVAL;
                                goto out;
                        }
  
                        if (compress_force) {
-                               btrfs_set_and_info(root, FORCE_COMPRESS,
-                                                  "force %s compression",
-                                                  compress_type);
+                               btrfs_set_opt(info->mount_opt, FORCE_COMPRESS);
                        } else {
-                               if (!btrfs_test_opt(root, COMPRESS))
-                                       btrfs_info(root->fs_info,
-                                                  "btrfs: use %s compression",
-                                                  compress_type);
                                /*
                                 * If we remount from compress-force=xxx to
                                 * compress=xxx, we need clear FORCE_COMPRESS
                                 */
                                btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
                        }
+                       if ((btrfs_test_opt(root, COMPRESS) &&
+                            (info->compress_type != saved_compress_type ||
+                             compress_force != saved_compress_force)) ||
+                           (!btrfs_test_opt(root, COMPRESS) &&
+                            no_compress == 1)) {
+                               btrfs_info(root->fs_info,
+                                          "%s %s compression",
+                                          (compress_force) ? "force" : "use",
+                                          compress_type);
+                       }
+                       compress_force = false;
                        break;
                case Opt_ssd:
                        btrfs_set_and_info(root, SSD,
@@@ -1549,7 -1564,9 +1564,7 @@@ static struct dentry *btrfs_mount(struc
                if ((flags ^ s->s_flags) & MS_RDONLY)
                        error = -EBUSY;
        } else {
 -              char b[BDEVNAME_SIZE];
 -
 -              strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
 +              snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
                btrfs_sb(s)->bdev_holder = fs_type;
                error = btrfs_fill_super(s, fs_devices, data,
                                         flags & MS_SILENT ? 1 : 0);