aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/relocation.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r--fs/btrfs/relocation.c126
1 files changed, 116 insertions, 10 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index b26a5aea41b4..8a2c2a07987b 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -31,6 +31,7 @@
31#include "async-thread.h" 31#include "async-thread.h"
32#include "free-space-cache.h" 32#include "free-space-cache.h"
33#include "inode-map.h" 33#include "inode-map.h"
34#include "qgroup.h"
34 35
35/* 36/*
36 * backref_node, mapping_node and tree_block start with this 37 * backref_node, mapping_node and tree_block start with this
@@ -3037,15 +3038,19 @@ int prealloc_file_extent_cluster(struct inode *inode,
3037 u64 num_bytes; 3038 u64 num_bytes;
3038 int nr = 0; 3039 int nr = 0;
3039 int ret = 0; 3040 int ret = 0;
3041 u64 prealloc_start = cluster->start - offset;
3042 u64 prealloc_end = cluster->end - offset;
3043 u64 cur_offset;
3040 3044
3041 BUG_ON(cluster->start != cluster->boundary[0]); 3045 BUG_ON(cluster->start != cluster->boundary[0]);
3042 inode_lock(inode); 3046 inode_lock(inode);
3043 3047
3044 ret = btrfs_check_data_free_space(inode, cluster->start, 3048 ret = btrfs_check_data_free_space(inode, prealloc_start,
3045 cluster->end + 1 - cluster->start); 3049 prealloc_end + 1 - prealloc_start);
3046 if (ret) 3050 if (ret)
3047 goto out; 3051 goto out;
3048 3052
3053 cur_offset = prealloc_start;
3049 while (nr < cluster->nr) { 3054 while (nr < cluster->nr) {
3050 start = cluster->boundary[nr] - offset; 3055 start = cluster->boundary[nr] - offset;
3051 if (nr + 1 < cluster->nr) 3056 if (nr + 1 < cluster->nr)
@@ -3055,16 +3060,21 @@ int prealloc_file_extent_cluster(struct inode *inode,
3055 3060
3056 lock_extent(&BTRFS_I(inode)->io_tree, start, end); 3061 lock_extent(&BTRFS_I(inode)->io_tree, start, end);
3057 num_bytes = end + 1 - start; 3062 num_bytes = end + 1 - start;
3063 if (cur_offset < start)
3064 btrfs_free_reserved_data_space(inode, cur_offset,
3065 start - cur_offset);
3058 ret = btrfs_prealloc_file_range(inode, 0, start, 3066 ret = btrfs_prealloc_file_range(inode, 0, start,
3059 num_bytes, num_bytes, 3067 num_bytes, num_bytes,
3060 end + 1, &alloc_hint); 3068 end + 1, &alloc_hint);
3069 cur_offset = end + 1;
3061 unlock_extent(&BTRFS_I(inode)->io_tree, start, end); 3070 unlock_extent(&BTRFS_I(inode)->io_tree, start, end);
3062 if (ret) 3071 if (ret)
3063 break; 3072 break;
3064 nr++; 3073 nr++;
3065 } 3074 }
3066 btrfs_free_reserved_data_space(inode, cluster->start, 3075 if (cur_offset < prealloc_end)
3067 cluster->end + 1 - cluster->start); 3076 btrfs_free_reserved_data_space(inode, cur_offset,
3077 prealloc_end + 1 - cur_offset);
3068out: 3078out:
3069 inode_unlock(inode); 3079 inode_unlock(inode);
3070 return ret; 3080 return ret;
@@ -3916,6 +3926,90 @@ int prepare_to_relocate(struct reloc_control *rc)
3916 return 0; 3926 return 0;
3917} 3927}
3918 3928
3929/*
3930 * Qgroup fixer for data chunk relocation.
3931 * The data relocation is done in the following steps
3932 * 1) Copy data extents into data reloc tree
3933 * 2) Create tree reloc tree(special snapshot) for related subvolumes
3934 * 3) Modify file extents in tree reloc tree
3935 * 4) Merge tree reloc tree with original fs tree, by swapping tree blocks
3936 *
3937 * The problem is, data and tree reloc tree are not accounted to qgroup,
3938 * and 4) will only info qgroup to track tree blocks change, not file extents
3939 * in the tree blocks.
3940 *
3941 * The good news is, related data extents are all in data reloc tree, so we
3942 * only need to info qgroup to track all file extents in data reloc tree
3943 * before commit trans.
3944 */
3945static int qgroup_fix_relocated_data_extents(struct btrfs_trans_handle *trans,
3946 struct reloc_control *rc)
3947{
3948 struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
3949 struct inode *inode = rc->data_inode;
3950 struct btrfs_root *data_reloc_root = BTRFS_I(inode)->root;
3951 struct btrfs_path *path;
3952 struct btrfs_key key;
3953 int ret = 0;
3954
3955 if (!fs_info->quota_enabled)
3956 return 0;
3957
3958 /*
3959 * Only for stage where we update data pointers the qgroup fix is
3960 * valid.
3961 * For MOVING_DATA stage, we will miss the timing of swapping tree
3962 * blocks, and won't fix it.
3963 */
3964 if (!(rc->stage == UPDATE_DATA_PTRS && rc->extents_found))
3965 return 0;
3966
3967 path = btrfs_alloc_path();
3968 if (!path)
3969 return -ENOMEM;
3970 key.objectid = btrfs_ino(inode);
3971 key.type = BTRFS_EXTENT_DATA_KEY;
3972 key.offset = 0;
3973
3974 ret = btrfs_search_slot(NULL, data_reloc_root, &key, path, 0, 0);
3975 if (ret < 0)
3976 goto out;
3977
3978 lock_extent(&BTRFS_I(inode)->io_tree, 0, (u64)-1);
3979 while (1) {
3980 struct btrfs_file_extent_item *fi;
3981
3982 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
3983 if (key.objectid > btrfs_ino(inode))
3984 break;
3985 if (key.type != BTRFS_EXTENT_DATA_KEY)
3986 goto next;
3987 fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
3988 struct btrfs_file_extent_item);
3989 if (btrfs_file_extent_type(path->nodes[0], fi) !=
3990 BTRFS_FILE_EXTENT_REG)
3991 goto next;
3992 ret = btrfs_qgroup_insert_dirty_extent(trans, fs_info,
3993 btrfs_file_extent_disk_bytenr(path->nodes[0], fi),
3994 btrfs_file_extent_disk_num_bytes(path->nodes[0], fi),
3995 GFP_NOFS);
3996 if (ret < 0)
3997 break;
3998next:
3999 ret = btrfs_next_item(data_reloc_root, path);
4000 if (ret < 0)
4001 break;
4002 if (ret > 0) {
4003 ret = 0;
4004 break;
4005 }
4006 }
4007 unlock_extent(&BTRFS_I(inode)->io_tree, 0 , (u64)-1);
4008out:
4009 btrfs_free_path(path);
4010 return ret;
4011}
4012
3919static noinline_for_stack int relocate_block_group(struct reloc_control *rc) 4013static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
3920{ 4014{
3921 struct rb_root blocks = RB_ROOT; 4015 struct rb_root blocks = RB_ROOT;
@@ -4102,10 +4196,16 @@ restart:
4102 4196
4103 /* get rid of pinned extents */ 4197 /* get rid of pinned extents */
4104 trans = btrfs_join_transaction(rc->extent_root); 4198 trans = btrfs_join_transaction(rc->extent_root);
4105 if (IS_ERR(trans)) 4199 if (IS_ERR(trans)) {
4106 err = PTR_ERR(trans); 4200 err = PTR_ERR(trans);
4107 else 4201 goto out_free;
4108 btrfs_commit_transaction(trans, rc->extent_root); 4202 }
4203 err = qgroup_fix_relocated_data_extents(trans, rc);
4204 if (err < 0) {
4205 btrfs_abort_transaction(trans, err);
4206 goto out_free;
4207 }
4208 btrfs_commit_transaction(trans, rc->extent_root);
4109out_free: 4209out_free:
4110 btrfs_free_block_rsv(rc->extent_root, rc->block_rsv); 4210 btrfs_free_block_rsv(rc->extent_root, rc->block_rsv);
4111 btrfs_free_path(path); 4211 btrfs_free_path(path);
@@ -4468,10 +4568,16 @@ int btrfs_recover_relocation(struct btrfs_root *root)
4468 unset_reloc_control(rc); 4568 unset_reloc_control(rc);
4469 4569
4470 trans = btrfs_join_transaction(rc->extent_root); 4570 trans = btrfs_join_transaction(rc->extent_root);
4471 if (IS_ERR(trans)) 4571 if (IS_ERR(trans)) {
4472 err = PTR_ERR(trans); 4572 err = PTR_ERR(trans);
4473 else 4573 goto out_free;
4474 err = btrfs_commit_transaction(trans, rc->extent_root); 4574 }
4575 err = qgroup_fix_relocated_data_extents(trans, rc);
4576 if (err < 0) {
4577 btrfs_abort_transaction(trans, err);
4578 goto out_free;
4579 }
4580 err = btrfs_commit_transaction(trans, rc->extent_root);
4475out_free: 4581out_free:
4476 kfree(rc); 4582 kfree(rc);
4477out: 4583out: