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, | 
