diff options
author | Dongsheng Yang <yangds.fnst@cn.fujitsu.com> | 2014-11-24 10:27:09 -0500 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-04-13 10:52:52 -0400 |
commit | f5a6b1c53bdd44f79e3904c0f5e59f956b49b2c8 (patch) | |
tree | 48a56daac94c95f58f3a6c10ef5c10bf0d7d0c19 | |
parent | 09870d2772b284d0061a5e4d1e1cdf6fb6764344 (diff) |
btrfs: qgroup: allow to remove qgroup which has parent but no child.
When a qgroup has parents but no child, it should be removable in
Theory I think. But currently, we can not remove it when it has
either parent or child.
Example:
# btrfs quota enable /mnt
# btrfs qgroup create 1/0 /mnt
# btrfs qgroup create 2/0 /mnt
# btrfs qgroup assign 1/0 2/0 /mnt
# btrfs qgroup show -pcre /mnt
qgroupid rfer excl max_rfer max_excl parent child
-------- ---- ---- -------- -------- ------ -----
0/5 16384 16384 0 0 --- ---
1/0 0 0 0 0 2/0 ---
2/0 0 0 0 0 --- 1/0
At this time, there is no subvol or qgroup depending on it.
Just a qgroup 2/0 is its parent, but 2/0 can work well without
1/0. So I think 1/0 should be removalbe. But:
# btrfs qgroup destroy 1/0 /mnt
ERROR: unable to destroy quota group: Device or resource busy
This patch remove the check of qgroup->parent in removing it,
then we can remove a qgroup when it has a parent.
Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r-- | fs/btrfs/qgroup.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 4ec86b3eee21..464d1e237512 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c | |||
@@ -1048,7 +1048,7 @@ out: | |||
1048 | return ret; | 1048 | return ret; |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, | 1051 | int __del_qgroup_relation(struct btrfs_trans_handle *trans, |
1052 | struct btrfs_fs_info *fs_info, u64 src, u64 dst) | 1052 | struct btrfs_fs_info *fs_info, u64 src, u64 dst) |
1053 | { | 1053 | { |
1054 | struct btrfs_root *quota_root; | 1054 | struct btrfs_root *quota_root; |
@@ -1058,7 +1058,6 @@ int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, | |||
1058 | int ret = 0; | 1058 | int ret = 0; |
1059 | int err; | 1059 | int err; |
1060 | 1060 | ||
1061 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
1062 | quota_root = fs_info->quota_root; | 1061 | quota_root = fs_info->quota_root; |
1063 | if (!quota_root) { | 1062 | if (!quota_root) { |
1064 | ret = -EINVAL; | 1063 | ret = -EINVAL; |
@@ -1089,7 +1088,18 @@ exist: | |||
1089 | del_relation_rb(fs_info, src, dst); | 1088 | del_relation_rb(fs_info, src, dst); |
1090 | spin_unlock(&fs_info->qgroup_lock); | 1089 | spin_unlock(&fs_info->qgroup_lock); |
1091 | out: | 1090 | out: |
1091 | return ret; | ||
1092 | } | ||
1093 | |||
1094 | int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, | ||
1095 | struct btrfs_fs_info *fs_info, u64 src, u64 dst) | ||
1096 | { | ||
1097 | int ret = 0; | ||
1098 | |||
1099 | mutex_lock(&fs_info->qgroup_ioctl_lock); | ||
1100 | ret = __del_qgroup_relation(trans, fs_info, src, dst); | ||
1092 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | 1101 | mutex_unlock(&fs_info->qgroup_ioctl_lock); |
1102 | |||
1093 | return ret; | 1103 | return ret; |
1094 | } | 1104 | } |
1095 | 1105 | ||
@@ -1132,6 +1142,7 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, | |||
1132 | { | 1142 | { |
1133 | struct btrfs_root *quota_root; | 1143 | struct btrfs_root *quota_root; |
1134 | struct btrfs_qgroup *qgroup; | 1144 | struct btrfs_qgroup *qgroup; |
1145 | struct btrfs_qgroup_list *list; | ||
1135 | int ret = 0; | 1146 | int ret = 0; |
1136 | 1147 | ||
1137 | mutex_lock(&fs_info->qgroup_ioctl_lock); | 1148 | mutex_lock(&fs_info->qgroup_ioctl_lock); |
@@ -1146,15 +1157,24 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, | |||
1146 | ret = -ENOENT; | 1157 | ret = -ENOENT; |
1147 | goto out; | 1158 | goto out; |
1148 | } else { | 1159 | } else { |
1149 | /* check if there are no relations to this qgroup */ | 1160 | /* check if there are no children of this qgroup */ |
1150 | if (!list_empty(&qgroup->groups) || | 1161 | if (!list_empty(&qgroup->members)) { |
1151 | !list_empty(&qgroup->members)) { | ||
1152 | ret = -EBUSY; | 1162 | ret = -EBUSY; |
1153 | goto out; | 1163 | goto out; |
1154 | } | 1164 | } |
1155 | } | 1165 | } |
1156 | ret = del_qgroup_item(trans, quota_root, qgroupid); | 1166 | ret = del_qgroup_item(trans, quota_root, qgroupid); |
1157 | 1167 | ||
1168 | while (!list_empty(&qgroup->groups)) { | ||
1169 | list = list_first_entry(&qgroup->groups, | ||
1170 | struct btrfs_qgroup_list, next_group); | ||
1171 | ret = __del_qgroup_relation(trans, fs_info, | ||
1172 | qgroupid, | ||
1173 | list->group->qgroupid); | ||
1174 | if (ret) | ||
1175 | goto out; | ||
1176 | } | ||
1177 | |||
1158 | spin_lock(&fs_info->qgroup_lock); | 1178 | spin_lock(&fs_info->qgroup_lock); |
1159 | del_qgroup_rb(quota_root->fs_info, qgroupid); | 1179 | del_qgroup_rb(quota_root->fs_info, qgroupid); |
1160 | spin_unlock(&fs_info->qgroup_lock); | 1180 | spin_unlock(&fs_info->qgroup_lock); |