diff options
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r-- | fs/btrfs/relocation.c | 109 |
1 files changed, 93 insertions, 16 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b37d723b9d4a..045c9c2b2d7e 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "locking.h" | 29 | #include "locking.h" |
30 | #include "btrfs_inode.h" | 30 | #include "btrfs_inode.h" |
31 | #include "async-thread.h" | 31 | #include "async-thread.h" |
32 | #include "free-space-cache.h" | ||
32 | 33 | ||
33 | /* | 34 | /* |
34 | * backref_node, mapping_node and tree_block start with this | 35 | * backref_node, mapping_node and tree_block start with this |
@@ -178,8 +179,6 @@ struct reloc_control { | |||
178 | u64 search_start; | 179 | u64 search_start; |
179 | u64 extents_found; | 180 | u64 extents_found; |
180 | 181 | ||
181 | int block_rsv_retries; | ||
182 | |||
183 | unsigned int stage:8; | 182 | unsigned int stage:8; |
184 | unsigned int create_reloc_tree:1; | 183 | unsigned int create_reloc_tree:1; |
185 | unsigned int merge_reloc_tree:1; | 184 | unsigned int merge_reloc_tree:1; |
@@ -2133,7 +2132,6 @@ int prepare_to_merge(struct reloc_control *rc, int err) | |||
2133 | LIST_HEAD(reloc_roots); | 2132 | LIST_HEAD(reloc_roots); |
2134 | u64 num_bytes = 0; | 2133 | u64 num_bytes = 0; |
2135 | int ret; | 2134 | int ret; |
2136 | int retries = 0; | ||
2137 | 2135 | ||
2138 | mutex_lock(&root->fs_info->trans_mutex); | 2136 | mutex_lock(&root->fs_info->trans_mutex); |
2139 | rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2; | 2137 | rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2; |
@@ -2143,7 +2141,7 @@ again: | |||
2143 | if (!err) { | 2141 | if (!err) { |
2144 | num_bytes = rc->merging_rsv_size; | 2142 | num_bytes = rc->merging_rsv_size; |
2145 | ret = btrfs_block_rsv_add(NULL, root, rc->block_rsv, | 2143 | ret = btrfs_block_rsv_add(NULL, root, rc->block_rsv, |
2146 | num_bytes, &retries); | 2144 | num_bytes); |
2147 | if (ret) | 2145 | if (ret) |
2148 | err = ret; | 2146 | err = ret; |
2149 | } | 2147 | } |
@@ -2155,7 +2153,6 @@ again: | |||
2155 | btrfs_end_transaction(trans, rc->extent_root); | 2153 | btrfs_end_transaction(trans, rc->extent_root); |
2156 | btrfs_block_rsv_release(rc->extent_root, | 2154 | btrfs_block_rsv_release(rc->extent_root, |
2157 | rc->block_rsv, num_bytes); | 2155 | rc->block_rsv, num_bytes); |
2158 | retries = 0; | ||
2159 | goto again; | 2156 | goto again; |
2160 | } | 2157 | } |
2161 | } | 2158 | } |
@@ -2405,15 +2402,13 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans, | |||
2405 | num_bytes = calcu_metadata_size(rc, node, 1) * 2; | 2402 | num_bytes = calcu_metadata_size(rc, node, 1) * 2; |
2406 | 2403 | ||
2407 | trans->block_rsv = rc->block_rsv; | 2404 | trans->block_rsv = rc->block_rsv; |
2408 | ret = btrfs_block_rsv_add(trans, root, rc->block_rsv, num_bytes, | 2405 | ret = btrfs_block_rsv_add(trans, root, rc->block_rsv, num_bytes); |
2409 | &rc->block_rsv_retries); | ||
2410 | if (ret) { | 2406 | if (ret) { |
2411 | if (ret == -EAGAIN) | 2407 | if (ret == -EAGAIN) |
2412 | rc->commit_transaction = 1; | 2408 | rc->commit_transaction = 1; |
2413 | return ret; | 2409 | return ret; |
2414 | } | 2410 | } |
2415 | 2411 | ||
2416 | rc->block_rsv_retries = 0; | ||
2417 | return 0; | 2412 | return 0; |
2418 | } | 2413 | } |
2419 | 2414 | ||
@@ -3099,6 +3094,8 @@ static int add_tree_block(struct reloc_control *rc, | |||
3099 | BUG_ON(item_size != sizeof(struct btrfs_extent_item_v0)); | 3094 | BUG_ON(item_size != sizeof(struct btrfs_extent_item_v0)); |
3100 | ret = get_ref_objectid_v0(rc, path, extent_key, | 3095 | ret = get_ref_objectid_v0(rc, path, extent_key, |
3101 | &ref_owner, NULL); | 3096 | &ref_owner, NULL); |
3097 | if (ret < 0) | ||
3098 | return ret; | ||
3102 | BUG_ON(ref_owner >= BTRFS_MAX_LEVEL); | 3099 | BUG_ON(ref_owner >= BTRFS_MAX_LEVEL); |
3103 | level = (int)ref_owner; | 3100 | level = (int)ref_owner; |
3104 | /* FIXME: get real generation */ | 3101 | /* FIXME: get real generation */ |
@@ -3191,6 +3188,54 @@ static int block_use_full_backref(struct reloc_control *rc, | |||
3191 | return ret; | 3188 | return ret; |
3192 | } | 3189 | } |
3193 | 3190 | ||
3191 | static int delete_block_group_cache(struct btrfs_fs_info *fs_info, | ||
3192 | struct inode *inode, u64 ino) | ||
3193 | { | ||
3194 | struct btrfs_key key; | ||
3195 | struct btrfs_path *path; | ||
3196 | struct btrfs_root *root = fs_info->tree_root; | ||
3197 | struct btrfs_trans_handle *trans; | ||
3198 | unsigned long nr; | ||
3199 | int ret = 0; | ||
3200 | |||
3201 | if (inode) | ||
3202 | goto truncate; | ||
3203 | |||
3204 | key.objectid = ino; | ||
3205 | key.type = BTRFS_INODE_ITEM_KEY; | ||
3206 | key.offset = 0; | ||
3207 | |||
3208 | inode = btrfs_iget(fs_info->sb, &key, root, NULL); | ||
3209 | if (!inode || IS_ERR(inode) || is_bad_inode(inode)) { | ||
3210 | if (inode && !IS_ERR(inode)) | ||
3211 | iput(inode); | ||
3212 | return -ENOENT; | ||
3213 | } | ||
3214 | |||
3215 | truncate: | ||
3216 | path = btrfs_alloc_path(); | ||
3217 | if (!path) { | ||
3218 | ret = -ENOMEM; | ||
3219 | goto out; | ||
3220 | } | ||
3221 | |||
3222 | trans = btrfs_join_transaction(root, 0); | ||
3223 | if (IS_ERR(trans)) { | ||
3224 | btrfs_free_path(path); | ||
3225 | goto out; | ||
3226 | } | ||
3227 | |||
3228 | ret = btrfs_truncate_free_space_cache(root, trans, path, inode); | ||
3229 | |||
3230 | btrfs_free_path(path); | ||
3231 | nr = trans->blocks_used; | ||
3232 | btrfs_end_transaction(trans, root); | ||
3233 | btrfs_btree_balance_dirty(root, nr); | ||
3234 | out: | ||
3235 | iput(inode); | ||
3236 | return ret; | ||
3237 | } | ||
3238 | |||
3194 | /* | 3239 | /* |
3195 | * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY | 3240 | * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY |
3196 | * this function scans fs tree to find blocks reference the data extent | 3241 | * this function scans fs tree to find blocks reference the data extent |
@@ -3217,15 +3262,27 @@ static int find_data_references(struct reloc_control *rc, | |||
3217 | int counted; | 3262 | int counted; |
3218 | int ret; | 3263 | int ret; |
3219 | 3264 | ||
3220 | path = btrfs_alloc_path(); | ||
3221 | if (!path) | ||
3222 | return -ENOMEM; | ||
3223 | |||
3224 | ref_root = btrfs_extent_data_ref_root(leaf, ref); | 3265 | ref_root = btrfs_extent_data_ref_root(leaf, ref); |
3225 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); | 3266 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); |
3226 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); | 3267 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); |
3227 | ref_count = btrfs_extent_data_ref_count(leaf, ref); | 3268 | ref_count = btrfs_extent_data_ref_count(leaf, ref); |
3228 | 3269 | ||
3270 | /* | ||
3271 | * This is an extent belonging to the free space cache, lets just delete | ||
3272 | * it and redo the search. | ||
3273 | */ | ||
3274 | if (ref_root == BTRFS_ROOT_TREE_OBJECTID) { | ||
3275 | ret = delete_block_group_cache(rc->extent_root->fs_info, | ||
3276 | NULL, ref_objectid); | ||
3277 | if (ret != -ENOENT) | ||
3278 | return ret; | ||
3279 | ret = 0; | ||
3280 | } | ||
3281 | |||
3282 | path = btrfs_alloc_path(); | ||
3283 | if (!path) | ||
3284 | return -ENOMEM; | ||
3285 | |||
3229 | root = read_fs_root(rc->extent_root->fs_info, ref_root); | 3286 | root = read_fs_root(rc->extent_root->fs_info, ref_root); |
3230 | if (IS_ERR(root)) { | 3287 | if (IS_ERR(root)) { |
3231 | err = PTR_ERR(root); | 3288 | err = PTR_ERR(root); |
@@ -3554,8 +3611,7 @@ int prepare_to_relocate(struct reloc_control *rc) | |||
3554 | * is no reservation in transaction handle. | 3611 | * is no reservation in transaction handle. |
3555 | */ | 3612 | */ |
3556 | ret = btrfs_block_rsv_add(NULL, rc->extent_root, rc->block_rsv, | 3613 | ret = btrfs_block_rsv_add(NULL, rc->extent_root, rc->block_rsv, |
3557 | rc->extent_root->nodesize * 256, | 3614 | rc->extent_root->nodesize * 256); |
3558 | &rc->block_rsv_retries); | ||
3559 | if (ret) | 3615 | if (ret) |
3560 | return ret; | 3616 | return ret; |
3561 | 3617 | ||
@@ -3567,7 +3623,6 @@ int prepare_to_relocate(struct reloc_control *rc) | |||
3567 | rc->extents_found = 0; | 3623 | rc->extents_found = 0; |
3568 | rc->nodes_relocated = 0; | 3624 | rc->nodes_relocated = 0; |
3569 | rc->merging_rsv_size = 0; | 3625 | rc->merging_rsv_size = 0; |
3570 | rc->block_rsv_retries = 0; | ||
3571 | 3626 | ||
3572 | rc->create_reloc_tree = 1; | 3627 | rc->create_reloc_tree = 1; |
3573 | set_reloc_control(rc); | 3628 | set_reloc_control(rc); |
@@ -3860,6 +3915,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
3860 | { | 3915 | { |
3861 | struct btrfs_fs_info *fs_info = extent_root->fs_info; | 3916 | struct btrfs_fs_info *fs_info = extent_root->fs_info; |
3862 | struct reloc_control *rc; | 3917 | struct reloc_control *rc; |
3918 | struct inode *inode; | ||
3919 | struct btrfs_path *path; | ||
3863 | int ret; | 3920 | int ret; |
3864 | int rw = 0; | 3921 | int rw = 0; |
3865 | int err = 0; | 3922 | int err = 0; |
@@ -3882,6 +3939,26 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
3882 | rw = 1; | 3939 | rw = 1; |
3883 | } | 3940 | } |
3884 | 3941 | ||
3942 | path = btrfs_alloc_path(); | ||
3943 | if (!path) { | ||
3944 | err = -ENOMEM; | ||
3945 | goto out; | ||
3946 | } | ||
3947 | |||
3948 | inode = lookup_free_space_inode(fs_info->tree_root, rc->block_group, | ||
3949 | path); | ||
3950 | btrfs_free_path(path); | ||
3951 | |||
3952 | if (!IS_ERR(inode)) | ||
3953 | ret = delete_block_group_cache(fs_info, inode, 0); | ||
3954 | else | ||
3955 | ret = PTR_ERR(inode); | ||
3956 | |||
3957 | if (ret && ret != -ENOENT) { | ||
3958 | err = ret; | ||
3959 | goto out; | ||
3960 | } | ||
3961 | |||
3885 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); | 3962 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); |
3886 | if (IS_ERR(rc->data_inode)) { | 3963 | if (IS_ERR(rc->data_inode)) { |
3887 | err = PTR_ERR(rc->data_inode); | 3964 | err = PTR_ERR(rc->data_inode); |
@@ -4143,7 +4220,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) | |||
4143 | btrfs_add_ordered_sum(inode, ordered, sums); | 4220 | btrfs_add_ordered_sum(inode, ordered, sums); |
4144 | } | 4221 | } |
4145 | btrfs_put_ordered_extent(ordered); | 4222 | btrfs_put_ordered_extent(ordered); |
4146 | return 0; | 4223 | return ret; |
4147 | } | 4224 | } |
4148 | 4225 | ||
4149 | void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, | 4226 | void btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, |