@@ -3997,6 +3997,8 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans,
char *name);
int btrfs_remove_qgroup(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 qgroupid);
+int btrfs_remove_subvolume_qgroup(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info, u64 qgroupid);
int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 qgroupid,
struct btrfs_qgroup_limit *limit);
@@ -2250,7 +2250,10 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
goto out_end_trans;
}
}
-
+ ret = btrfs_remove_subvolume_qgroup(trans, root->fs_info,
+ dest->root_key.objectid);
+ if (ret)
+ btrfs_abort_transaction(trans, root, ret);
out_end_trans:
trans->block_rsv = NULL;
trans->bytes_reserved = 0;
@@ -1985,3 +1985,68 @@ btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info)
btrfs_queue_worker(&fs_info->qgroup_rescan_workers,
&fs_info->qgroup_rescan_work);
}
+
+int btrfs_remove_subvolume_qgroup(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ u64 qgroupid)
+{
+ struct btrfs_root *quota_root;
+ struct btrfs_qgroup *qgroup;
+ struct btrfs_qgroup_list *list;
+ int ret = 0;
+
+ mutex_lock(&fs_info->qgroup_ioctl_lock);
+ quota_root = fs_info->quota_root;
+ if (!quota_root) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ qgroup = find_qgroup_rb(fs_info, qgroupid);
+ if (!qgroup) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ list_for_each_entry(list, &qgroup->groups, next_group) {
+ ret = del_qgroup_relation_item(trans, quota_root, qgroupid,
+ list->group->qgroupid);
+ if (ret && ret != -ENOENT)
+ goto out;
+ ret = del_qgroup_relation_item(trans, quota_root,
+ list->group->qgroupid, qgroupid);
+ if (ret && ret != -ENOENT)
+ goto out;
+ }
+
+ /*
+ * this should not happen with strict hierarchical level
+ * qgroup.
+ */
+ list_for_each_entry(list, &qgroup->members, next_group) {
+ ret = del_qgroup_relation_item(trans, quota_root,
+ list->member->qgroupid, qgroupid);
+ if (ret && ret != -ENOENT)
+ goto out;
+ ret = del_qgroup_relation_item(trans, quota_root,
+ qgroupid, list->member->qgroupid);
+ if (ret && ret != -ENOENT)
+ goto out;
+ }
+ ret = del_qgroup_item(trans, quota_root, qgroupid);
+ if (ret && ret != -ENOENT)
+ goto out;
+ spin_lock(&fs_info->qgroup_lock);
+ ret = qgroup_account_ref_step2(quota_root->fs_info,
+ quota_root->fs_info->qgroup_ulist, -1,
+ qgroup->rfer, qgroup);
+ del_qgroup_rb(quota_root->fs_info, qgroupid);
+ spin_unlock(&fs_info->qgroup_lock);
+out:
+ mutex_unlock(&fs_info->qgroup_ioctl_lock);
+ if (ret == -ENOENT)
+ ret = 0;
+ return ret;
+
+}
+