From: Wang Shilong <wangsl-f...@cn.fujitsu.com>

The original code dosen't have necessary checks before
doing qgroup_inherit. Fix it.

Signed-off-by: Wang Shilong <wangsl-f...@cn.fujitsu.com>
Reviewed-by: Miao Xie <mi...@cn.fujitsu.com>
---
 fs/btrfs/ioctl.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 1cd96f6..86e7fb3 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -708,6 +708,49 @@ static inline int btrfs_may_create(struct inode *dir, 
struct dentry *child)
        return inode_permission(dir, MAY_WRITE | MAY_EXEC);
 }
 
+static int check_qgroup_inherit(struct btrfs_root *root,
+                               struct btrfs_qgroup_inherit *inherit)
+{
+       int ret = 0;
+       u64 *i_qgroups;
+       u64 nums = 0;
+       u64 i = 0;
+       struct btrfs_path *path;
+       struct btrfs_key key;
+
+       if (!inherit)
+               return 0;
+       if (!root->fs_info->quota_root)
+               return -EINVAL;
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       i_qgroups = (u64 *)(inherit + 1);
+       nums = inherit->num_qgroups + inherit->num_ref_copies +
+              inherit->num_excl_copies;
+       for (i = 0; i < nums; ++i) {
+               btrfs_release_path(path);
+               key.objectid = 0;
+               key.type = BTRFS_QGROUP_INFO_KEY;
+               key.offset = *i_qgroups;
+
+               ret = btrfs_search_slot(NULL, root->fs_info->quota_root,
+                                       &key, path, 0, 0);
+               if (ret > 0)
+                       ret = -EINVAL;
+               if (ret)
+                       goto out;
+               ++i_qgroups;
+       }
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 /*
  * Create a new subvolume below @parent.  This is largely modeled after
  * sys_mkdirat and vfs_mkdir, but we only do a single component lookup
@@ -753,6 +796,11 @@ static noinline int btrfs_mksubvol(struct path *parent,
        if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0)
                goto out_up_read;
 
+       mutex_lock(&BTRFS_I(dir)->root->fs_info->quota_lock);
+       error = check_qgroup_inherit(BTRFS_I(dir)->root, inherit);
+       if (error)
+               goto out_unlock_mutex;
+
        if (snap_src) {
                error = create_snapshot(snap_src, dir, dentry, name, namelen,
                                        async_transid, readonly, inherit);
@@ -762,6 +810,8 @@ static noinline int btrfs_mksubvol(struct path *parent,
        }
        if (!error)
                fsnotify_mkdir(dir, dentry);
+out_unlock_mutex:
+       mutex_unlock(&BTRFS_I(dir)->root->fs_info->quota_lock);
 out_up_read:
        up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem);
 out_dput:
-- 
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to