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