]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/btrfs/ioctl.c
Merge branch 'qgroup' of git://git.jan-o-sch.net/btrfs-unstable into for-linus
[mirror_ubuntu-bionic-kernel.git] / fs / btrfs / ioctl.c
index 1dffd0adf975fcd2aa3c54f3bd991928384ec245..e54b663fd3aab34972ee5a4d3ee21a54617df289 100644 (file)
@@ -663,13 +663,9 @@ static noinline int btrfs_mksubvol(struct path *parent,
        if (dentry->d_inode)
                goto out_dput;
 
-       error = mnt_want_write(parent->mnt);
-       if (error)
-               goto out_dput;
-
        error = btrfs_may_create(dir, dentry);
        if (error)
-               goto out_drop_write;
+               goto out_dput;
 
        down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem);
 
@@ -687,8 +683,6 @@ static noinline int btrfs_mksubvol(struct path *parent,
                fsnotify_mkdir(dir, dentry);
 out_up_read:
        up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem);
-out_drop_write:
-       mnt_drop_write(parent->mnt);
 out_dput:
        dput(dentry);
 out_unlock:
@@ -843,7 +837,8 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em)
 }
 
 static int should_defrag_range(struct inode *inode, u64 start, int thresh,
-                              u64 *last_len, u64 *skip, u64 *defrag_end)
+                              u64 *last_len, u64 *skip, u64 *defrag_end,
+                              int compress)
 {
        struct extent_map *em;
        int ret = 1;
@@ -874,7 +869,7 @@ static int should_defrag_range(struct inode *inode, u64 start, int thresh,
         * we hit a real extent, if it is big or the next extent is not a
         * real extent, don't bother defragging it
         */
-       if ((*last_len == 0 || *last_len >= thresh) &&
+       if (!compress && (*last_len == 0 || *last_len >= thresh) &&
            (em->len >= thresh || !next_mergeable))
                ret = 0;
 out:
@@ -1156,7 +1151,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
 
                if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,
                                         extent_thresh, &last_len, &skip,
-                                        &defrag_end)) {
+                                        &defrag_end, range->flags &
+                                        BTRFS_DEFRAG_RANGE_COMPRESS)) {
                        unsigned long next;
                        /*
                         * the should_defrag function tells us how much to skip
@@ -1394,24 +1390,24 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
                                u64 *transid, bool readonly,
                                struct btrfs_qgroup_inherit **inherit)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct file *src_file;
        int namelen;
        int ret = 0;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               goto out;
 
        namelen = strlen(name);
        if (strchr(name, '/')) {
                ret = -EINVAL;
-               goto out;
+               goto out_drop_write;
        }
 
        if (name[0] == '.' &&
           (namelen == 1 || (name[1] == '.' && namelen == 2))) {
                ret = -EEXIST;
-               goto out;
+               goto out_drop_write;
        }
 
        if (subvol) {
@@ -1422,7 +1418,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
                src_file = fget(fd);
                if (!src_file) {
                        ret = -EINVAL;
-                       goto out;
+                       goto out_drop_write;
                }
 
                src_inode = src_file->f_path.dentry->d_inode;
@@ -1431,13 +1427,15 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
                               "another FS\n");
                        ret = -EINVAL;
                        fput(src_file);
-                       goto out;
+                       goto out_drop_write;
                }
                ret = btrfs_mksubvol(&file->f_path, name, namelen,
                                     BTRFS_I(src_inode)->root,
                                     transid, readonly, inherit);
                fput(src_file);
        }
+out_drop_write:
+       mnt_drop_write_file(file);
 out:
        return ret;
 }
@@ -1546,29 +1544,40 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
        u64 flags;
        int ret = 0;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               goto out;
 
-       if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
-               return -EINVAL;
+       if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
+               ret = -EINVAL;
+               goto out_drop_write;
+       }
 
-       if (copy_from_user(&flags, arg, sizeof(flags)))
-               return -EFAULT;
+       if (copy_from_user(&flags, arg, sizeof(flags))) {
+               ret = -EFAULT;
+               goto out_drop_write;
+       }
 
-       if (flags & BTRFS_SUBVOL_CREATE_ASYNC)
-               return -EINVAL;
+       if (flags & BTRFS_SUBVOL_CREATE_ASYNC) {
+               ret = -EINVAL;
+               goto out_drop_write;
+       }
 
-       if (flags & ~BTRFS_SUBVOL_RDONLY)
-               return -EOPNOTSUPP;
+       if (flags & ~BTRFS_SUBVOL_RDONLY) {
+               ret = -EOPNOTSUPP;
+               goto out_drop_write;
+       }
 
-       if (!inode_owner_or_capable(inode))
-               return -EACCES;
+       if (!inode_owner_or_capable(inode)) {
+               ret = -EACCES;
+               goto out_drop_write;
+       }
 
        down_write(&root->fs_info->subvol_sem);
 
        /* nothing to do */
        if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root))
-               goto out;
+               goto out_drop_sem;
 
        root_flags = btrfs_root_flags(&root->root_item);
        if (flags & BTRFS_SUBVOL_RDONLY)
@@ -1591,8 +1600,11 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
 out_reset:
        if (ret)
                btrfs_set_root_flags(&root->root_item, root_flags);
-out:
+out_drop_sem:
        up_write(&root->fs_info->subvol_sem);
+out_drop_write:
+       mnt_drop_write_file(file);
+out:
        return ret;
 }
 
@@ -3086,19 +3098,21 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
 }
 
 static long btrfs_ioctl_get_dev_stats(struct btrfs_root *root,
-                                     void __user *arg, int reset_after_read)
+                                     void __user *arg)
 {
        struct btrfs_ioctl_get_dev_stats *sa;
        int ret;
 
-       if (reset_after_read && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
        sa = memdup_user(arg, sizeof(*sa));
        if (IS_ERR(sa))
                return PTR_ERR(sa);
 
-       ret = btrfs_get_dev_stats(root, sa, reset_after_read);
+       if ((sa->flags & BTRFS_DEV_STATS_RESET) && !capable(CAP_SYS_ADMIN)) {
+               kfree(sa);
+               return -EPERM;
+       }
+
+       ret = btrfs_get_dev_stats(root, sa);
 
        if (copy_to_user(arg, sa, sizeof(*sa)))
                ret = -EFAULT;
@@ -3288,10 +3302,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
-
-       ret = mnt_want_write(file->f_path.mnt);
+       ret = mnt_want_write_file(file);
        if (ret)
                return ret;
 
@@ -3361,7 +3372,7 @@ out_bargs:
 out:
        mutex_unlock(&fs_info->balance_mutex);
        mutex_unlock(&fs_info->volume_mutex);
-       mnt_drop_write(file->f_path.mnt);
+       mnt_drop_write_file(file);
        return ret;
 }
 
@@ -3675,9 +3686,7 @@ long btrfs_ioctl(struct file *file, unsigned int
        case BTRFS_IOC_BALANCE_PROGRESS:
                return btrfs_ioctl_balance_progress(root, argp);
        case BTRFS_IOC_GET_DEV_STATS:
-               return btrfs_ioctl_get_dev_stats(root, argp, 0);
-       case BTRFS_IOC_GET_AND_RESET_DEV_STATS:
-               return btrfs_ioctl_get_dev_stats(root, argp, 1);
+               return btrfs_ioctl_get_dev_stats(root, argp);
        case BTRFS_IOC_QUOTA_CTL:
                return btrfs_ioctl_quota_ctl(root, argp);
        case BTRFS_IOC_QGROUP_ASSIGN: