@@ -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: