diff options
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r-- | fs/btrfs/relocation.c | 91 |
1 files changed, 87 insertions, 4 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b37d723b9d4a..af339eee55b8 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 |
@@ -3191,6 +3192,54 @@ static int block_use_full_backref(struct reloc_control *rc, | |||
3191 | return ret; | 3192 | return ret; |
3192 | } | 3193 | } |
3193 | 3194 | ||
3195 | static int delete_block_group_cache(struct btrfs_fs_info *fs_info, | ||
3196 | struct inode *inode, u64 ino) | ||
3197 | { | ||
3198 | struct btrfs_key key; | ||
3199 | struct btrfs_path *path; | ||
3200 | struct btrfs_root *root = fs_info->tree_root; | ||
3201 | struct btrfs_trans_handle *trans; | ||
3202 | unsigned long nr; | ||
3203 | int ret = 0; | ||
3204 | |||
3205 | if (inode) | ||
3206 | goto truncate; | ||
3207 | |||
3208 | key.objectid = ino; | ||
3209 | key.type = BTRFS_INODE_ITEM_KEY; | ||
3210 | key.offset = 0; | ||
3211 | |||
3212 | inode = btrfs_iget(fs_info->sb, &key, root, NULL); | ||
3213 | if (!inode || IS_ERR(inode) || is_bad_inode(inode)) { | ||
3214 | if (inode && !IS_ERR(inode)) | ||
3215 | iput(inode); | ||
3216 | return -ENOENT; | ||
3217 | } | ||
3218 | |||
3219 | truncate: | ||
3220 | path = btrfs_alloc_path(); | ||
3221 | if (!path) { | ||
3222 | ret = -ENOMEM; | ||
3223 | goto out; | ||
3224 | } | ||
3225 | |||
3226 | trans = btrfs_join_transaction(root, 0); | ||
3227 | if (IS_ERR(trans)) { | ||
3228 | btrfs_free_path(path); | ||
3229 | goto out; | ||
3230 | } | ||
3231 | |||
3232 | ret = btrfs_truncate_free_space_cache(root, trans, path, inode); | ||
3233 | |||
3234 | btrfs_free_path(path); | ||
3235 | nr = trans->blocks_used; | ||
3236 | btrfs_end_transaction(trans, root); | ||
3237 | btrfs_btree_balance_dirty(root, nr); | ||
3238 | out: | ||
3239 | iput(inode); | ||
3240 | return ret; | ||
3241 | } | ||
3242 | |||
3194 | /* | 3243 | /* |
3195 | * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY | 3244 | * 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 | 3245 | * this function scans fs tree to find blocks reference the data extent |
@@ -3217,15 +3266,27 @@ static int find_data_references(struct reloc_control *rc, | |||
3217 | int counted; | 3266 | int counted; |
3218 | int ret; | 3267 | int ret; |
3219 | 3268 | ||
3220 | path = btrfs_alloc_path(); | ||
3221 | if (!path) | ||
3222 | return -ENOMEM; | ||
3223 | |||
3224 | ref_root = btrfs_extent_data_ref_root(leaf, ref); | 3269 | ref_root = btrfs_extent_data_ref_root(leaf, ref); |
3225 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); | 3270 | ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); |
3226 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); | 3271 | ref_offset = btrfs_extent_data_ref_offset(leaf, ref); |
3227 | ref_count = btrfs_extent_data_ref_count(leaf, ref); | 3272 | ref_count = btrfs_extent_data_ref_count(leaf, ref); |
3228 | 3273 | ||
3274 | /* | ||
3275 | * This is an extent belonging to the free space cache, lets just delete | ||
3276 | * it and redo the search. | ||
3277 | */ | ||
3278 | if (ref_root == BTRFS_ROOT_TREE_OBJECTID) { | ||
3279 | ret = delete_block_group_cache(rc->extent_root->fs_info, | ||
3280 | NULL, ref_objectid); | ||
3281 | if (ret != -ENOENT) | ||
3282 | return ret; | ||
3283 | ret = 0; | ||
3284 | } | ||
3285 | |||
3286 | path = btrfs_alloc_path(); | ||
3287 | if (!path) | ||
3288 | return -ENOMEM; | ||
3289 | |||
3229 | root = read_fs_root(rc->extent_root->fs_info, ref_root); | 3290 | root = read_fs_root(rc->extent_root->fs_info, ref_root); |
3230 | if (IS_ERR(root)) { | 3291 | if (IS_ERR(root)) { |
3231 | err = PTR_ERR(root); | 3292 | err = PTR_ERR(root); |
@@ -3860,6 +3921,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
3860 | { | 3921 | { |
3861 | struct btrfs_fs_info *fs_info = extent_root->fs_info; | 3922 | struct btrfs_fs_info *fs_info = extent_root->fs_info; |
3862 | struct reloc_control *rc; | 3923 | struct reloc_control *rc; |
3924 | struct inode *inode; | ||
3925 | struct btrfs_path *path; | ||
3863 | int ret; | 3926 | int ret; |
3864 | int rw = 0; | 3927 | int rw = 0; |
3865 | int err = 0; | 3928 | int err = 0; |
@@ -3882,6 +3945,26 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) | |||
3882 | rw = 1; | 3945 | rw = 1; |
3883 | } | 3946 | } |
3884 | 3947 | ||
3948 | path = btrfs_alloc_path(); | ||
3949 | if (!path) { | ||
3950 | err = -ENOMEM; | ||
3951 | goto out; | ||
3952 | } | ||
3953 | |||
3954 | inode = lookup_free_space_inode(fs_info->tree_root, rc->block_group, | ||
3955 | path); | ||
3956 | btrfs_free_path(path); | ||
3957 | |||
3958 | if (!IS_ERR(inode)) | ||
3959 | ret = delete_block_group_cache(fs_info, inode, 0); | ||
3960 | else | ||
3961 | ret = PTR_ERR(inode); | ||
3962 | |||
3963 | if (ret && ret != -ENOENT) { | ||
3964 | err = ret; | ||
3965 | goto out; | ||
3966 | } | ||
3967 | |||
3885 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); | 3968 | rc->data_inode = create_reloc_inode(fs_info, rc->block_group); |
3886 | if (IS_ERR(rc->data_inode)) { | 3969 | if (IS_ERR(rc->data_inode)) { |
3887 | err = PTR_ERR(rc->data_inode); | 3970 | err = PTR_ERR(rc->data_inode); |