@@ -3827,6 +3827,8 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
int btrfs_quota_disable(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_quota_rescan(struct btrfs_fs_info *fs_info);
+int btrfs_may_assign_qgroup(struct btrfs_root *root,
+ struct btrfs_ioctl_qgroup_assign_args *sa);
int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 src, u64 dst);
int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
@@ -3758,13 +3758,15 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
}
mutex_lock(&root->fs_info->quota_lock);
+ ret = btrfs_may_assign_qgroup(root, sa);
+ if (ret)
+ goto out;
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
- /* FIXME: check if the IDs really exist */
if (sa->assign) {
ret = btrfs_add_qgroup_relation(trans, root->fs_info,
sa->src, sa->dst);
@@ -952,13 +952,9 @@ int btrfs_quota_rescan(struct btrfs_fs_info *fs_info)
int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 src, u64 dst)
{
- struct btrfs_root *quota_root;
+ struct btrfs_root *quota_root = fs_info->quota_root;
int ret = 0;
- quota_root = fs_info->quota_root;
- if (!quota_root)
- return -EINVAL;
-
ret = add_qgroup_relation_item(trans, quota_root, src, dst);
if (ret)
return ret;
@@ -979,14 +975,10 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 src, u64 dst)
{
- struct btrfs_root *quota_root;
+ struct btrfs_root *quota_root = fs_info->quota_root;
int ret = 0;
int err;
- quota_root = fs_info->quota_root;
- if (!quota_root)
- return -EINVAL;
-
ret = del_qgroup_relation_item(trans, quota_root, src, dst);
err = del_qgroup_relation_item(trans, quota_root, dst, src);
if (err && !ret)
@@ -1681,3 +1673,31 @@ int btrfs_may_create_qgroup(struct btrfs_root *root,
return -EBUSY;
return 0;
}
+
+int btrfs_may_assign_qgroup(struct btrfs_root *root,
+ struct btrfs_ioctl_qgroup_assign_args *sa)
+{
+
+ struct btrfs_qgroup *parent = NULL;
+ struct btrfs_qgroup *member = NULL;
+ struct btrfs_qgroup_list *list;
+
+ if (!root->fs_info->quota_root)
+ return -EINVAL;
+
+ member = find_qgroup_rb(root->fs_info, sa->src);
+ parent = find_qgroup_rb(root->fs_info, sa->dst);
+ if (!member || !parent)
+ return -ENOENT;
+
+ list_for_each_entry(list, &member->groups, next_group) {
+ if (list->group == parent) {
+ if (sa->assign)
+ return -EEXIST;
+ return 0;
+ }
+ }
+ if (sa->assign)
+ return 0;
+ return -ENOENT;
+}