diff options
Diffstat (limited to 'fs/btrfs/qgroup.c')
| -rw-r--r-- | fs/btrfs/qgroup.c | 69 | 
1 files changed, 28 insertions, 41 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 1280eff8af56..4e6ef490619e 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c  | |||
| @@ -157,18 +157,11 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info, | |||
| 157 | return qgroup; | 157 | return qgroup; | 
| 158 | } | 158 | } | 
| 159 | 159 | ||
| 160 | /* must be called with qgroup_lock held */ | 160 | static void __del_qgroup_rb(struct btrfs_qgroup *qgroup) | 
| 161 | static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid) | ||
| 162 | { | 161 | { | 
| 163 | struct btrfs_qgroup *qgroup = find_qgroup_rb(fs_info, qgroupid); | ||
| 164 | struct btrfs_qgroup_list *list; | 162 | struct btrfs_qgroup_list *list; | 
| 165 | 163 | ||
| 166 | if (!qgroup) | ||
| 167 | return -ENOENT; | ||
| 168 | |||
| 169 | rb_erase(&qgroup->node, &fs_info->qgroup_tree); | ||
| 170 | list_del(&qgroup->dirty); | 164 | list_del(&qgroup->dirty); | 
| 171 | |||
| 172 | while (!list_empty(&qgroup->groups)) { | 165 | while (!list_empty(&qgroup->groups)) { | 
| 173 | list = list_first_entry(&qgroup->groups, | 166 | list = list_first_entry(&qgroup->groups, | 
| 174 | struct btrfs_qgroup_list, next_group); | 167 | struct btrfs_qgroup_list, next_group); | 
| @@ -185,7 +178,18 @@ static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid) | |||
| 185 | kfree(list); | 178 | kfree(list); | 
| 186 | } | 179 | } | 
| 187 | kfree(qgroup); | 180 | kfree(qgroup); | 
| 181 | } | ||
| 188 | 182 | ||
| 183 | /* must be called with qgroup_lock held */ | ||
| 184 | static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid) | ||
| 185 | { | ||
| 186 | struct btrfs_qgroup *qgroup = find_qgroup_rb(fs_info, qgroupid); | ||
| 187 | |||
| 188 | if (!qgroup) | ||
| 189 | return -ENOENT; | ||
| 190 | |||
| 191 | rb_erase(&qgroup->node, &fs_info->qgroup_tree); | ||
| 192 | __del_qgroup_rb(qgroup); | ||
| 189 | return 0; | 193 | return 0; | 
| 190 | } | 194 | } | 
| 191 | 195 | ||
| @@ -394,8 +398,7 @@ next1: | |||
| 394 | if (ret == -ENOENT) { | 398 | if (ret == -ENOENT) { | 
| 395 | printk(KERN_WARNING | 399 | printk(KERN_WARNING | 
| 396 | "btrfs: orphan qgroup relation 0x%llx->0x%llx\n", | 400 | "btrfs: orphan qgroup relation 0x%llx->0x%llx\n", | 
| 397 | (unsigned long long)found_key.objectid, | 401 | found_key.objectid, found_key.offset); | 
| 398 | (unsigned long long)found_key.offset); | ||
| 399 | ret = 0; /* ignore the error */ | 402 | ret = 0; /* ignore the error */ | 
| 400 | } | 403 | } | 
| 401 | if (ret) | 404 | if (ret) | 
| @@ -428,39 +431,28 @@ out: | |||
| 428 | } | 431 | } | 
| 429 | 432 | ||
| 430 | /* | 433 | /* | 
| 431 | * This is only called from close_ctree() or open_ctree(), both in single- | 434 | * This is called from close_ctree() or open_ctree() or btrfs_quota_disable(), | 
| 432 | * treaded paths. Clean up the in-memory structures. No locking needed. | 435 | * first two are in single-threaded paths.And for the third one, we have set | 
| 436 | * quota_root to be null with qgroup_lock held before, so it is safe to clean | ||
| 437 | * up the in-memory structures without qgroup_lock held. | ||
| 433 | */ | 438 | */ | 
| 434 | void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) | 439 | void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) | 
| 435 | { | 440 | { | 
| 436 | struct rb_node *n; | 441 | struct rb_node *n; | 
| 437 | struct btrfs_qgroup *qgroup; | 442 | struct btrfs_qgroup *qgroup; | 
| 438 | struct btrfs_qgroup_list *list; | ||
| 439 | 443 | ||
| 440 | while ((n = rb_first(&fs_info->qgroup_tree))) { | 444 | while ((n = rb_first(&fs_info->qgroup_tree))) { | 
| 441 | qgroup = rb_entry(n, struct btrfs_qgroup, node); | 445 | qgroup = rb_entry(n, struct btrfs_qgroup, node); | 
| 442 | rb_erase(n, &fs_info->qgroup_tree); | 446 | rb_erase(n, &fs_info->qgroup_tree); | 
| 443 | 447 | __del_qgroup_rb(qgroup); | |
| 444 | while (!list_empty(&qgroup->groups)) { | ||
| 445 | list = list_first_entry(&qgroup->groups, | ||
| 446 | struct btrfs_qgroup_list, | ||
| 447 | next_group); | ||
| 448 | list_del(&list->next_group); | ||
| 449 | list_del(&list->next_member); | ||
| 450 | kfree(list); | ||
| 451 | } | ||
| 452 | |||
| 453 | while (!list_empty(&qgroup->members)) { | ||
| 454 | list = list_first_entry(&qgroup->members, | ||
| 455 | struct btrfs_qgroup_list, | ||
| 456 | next_member); | ||
| 457 | list_del(&list->next_group); | ||
| 458 | list_del(&list->next_member); | ||
| 459 | kfree(list); | ||
| 460 | } | ||
| 461 | kfree(qgroup); | ||
| 462 | } | 448 | } | 
| 449 | /* | ||
| 450 | * we call btrfs_free_qgroup_config() when umounting | ||
| 451 | * filesystem and disabling quota, so we set qgroup_ulit | ||
| 452 | * to be null here to avoid double free. | ||
| 453 | */ | ||
| 463 | ulist_free(fs_info->qgroup_ulist); | 454 | ulist_free(fs_info->qgroup_ulist); | 
| 455 | fs_info->qgroup_ulist = NULL; | ||
| 464 | } | 456 | } | 
| 465 | 457 | ||
| 466 | static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, | 458 | static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, | 
| @@ -946,13 +938,9 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans, | |||
| 946 | fs_info->pending_quota_state = 0; | 938 | fs_info->pending_quota_state = 0; | 
| 947 | quota_root = fs_info->quota_root; | 939 | quota_root = fs_info->quota_root; | 
| 948 | fs_info->quota_root = NULL; | 940 | fs_info->quota_root = NULL; | 
| 949 | btrfs_free_qgroup_config(fs_info); | ||
| 950 | spin_unlock(&fs_info->qgroup_lock); | 941 | spin_unlock(&fs_info->qgroup_lock); | 
| 951 | 942 | ||
| 952 | if (!quota_root) { | 943 | btrfs_free_qgroup_config(fs_info); | 
| 953 | ret = -EINVAL; | ||
| 954 | goto out; | ||
| 955 | } | ||
| 956 | 944 | ||
| 957 | ret = btrfs_clean_quota_tree(trans, quota_root); | 945 | ret = btrfs_clean_quota_tree(trans, quota_root); | 
| 958 | if (ret) | 946 | if (ret) | 
| @@ -1174,7 +1162,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, | |||
| 1174 | if (ret) { | 1162 | if (ret) { | 
| 1175 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | 1163 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | 
| 1176 | printk(KERN_INFO "unable to update quota limit for %llu\n", | 1164 | printk(KERN_INFO "unable to update quota limit for %llu\n", | 
| 1177 | (unsigned long long)qgroupid); | 1165 | qgroupid); | 
| 1178 | } | 1166 | } | 
| 1179 | 1167 | ||
| 1180 | spin_lock(&fs_info->qgroup_lock); | 1168 | spin_lock(&fs_info->qgroup_lock); | 
| @@ -1884,10 +1872,9 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, | |||
| 1884 | path, 1, 0); | 1872 | path, 1, 0); | 
| 1885 | 1873 | ||
| 1886 | pr_debug("current progress key (%llu %u %llu), search_slot ret %d\n", | 1874 | pr_debug("current progress key (%llu %u %llu), search_slot ret %d\n", | 
| 1887 | (unsigned long long)fs_info->qgroup_rescan_progress.objectid, | 1875 | fs_info->qgroup_rescan_progress.objectid, | 
| 1888 | fs_info->qgroup_rescan_progress.type, | 1876 | fs_info->qgroup_rescan_progress.type, | 
| 1889 | (unsigned long long)fs_info->qgroup_rescan_progress.offset, | 1877 | fs_info->qgroup_rescan_progress.offset, ret); | 
| 1890 | ret); | ||
| 1891 | 1878 | ||
| 1892 | if (ret) { | 1879 | if (ret) { | 
| 1893 | /* | 1880 | /* | 
