diff options
Diffstat (limited to 'fs/btrfs/tree-defrag.c')
-rw-r--r-- | fs/btrfs/tree-defrag.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index 7ea66b4aa5c2..a09064a9a41c 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c | |||
@@ -42,16 +42,20 @@ static void reada_defrag(struct btrfs_root *root, | |||
42 | static int defrag_walk_down(struct btrfs_trans_handle *trans, | 42 | static int defrag_walk_down(struct btrfs_trans_handle *trans, |
43 | struct btrfs_root *root, | 43 | struct btrfs_root *root, |
44 | struct btrfs_path *path, int *level, | 44 | struct btrfs_path *path, int *level, |
45 | int cache_only) | 45 | int cache_only, u64 *last_ret) |
46 | { | 46 | { |
47 | struct buffer_head *next; | 47 | struct buffer_head *next; |
48 | struct buffer_head *cur; | 48 | struct buffer_head *cur; |
49 | u64 blocknr; | 49 | u64 blocknr; |
50 | int ret = 0; | 50 | int ret = 0; |
51 | int is_extent = 0; | ||
51 | 52 | ||
52 | WARN_ON(*level < 0); | 53 | WARN_ON(*level < 0); |
53 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 54 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
54 | 55 | ||
56 | if (root->fs_info->extent_root == root) | ||
57 | is_extent = 1; | ||
58 | |||
55 | while(*level > 0) { | 59 | while(*level > 0) { |
56 | WARN_ON(*level < 0); | 60 | WARN_ON(*level < 0); |
57 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 61 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
@@ -70,7 +74,10 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
70 | if (*level == 1) { | 74 | if (*level == 1) { |
71 | ret = btrfs_realloc_node(trans, root, | 75 | ret = btrfs_realloc_node(trans, root, |
72 | path->nodes[*level], | 76 | path->nodes[*level], |
73 | cache_only); | 77 | cache_only, last_ret); |
78 | if (is_extent) | ||
79 | btrfs_extent_post_op(trans, root); | ||
80 | |||
74 | break; | 81 | break; |
75 | } | 82 | } |
76 | blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur), | 83 | blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur), |
@@ -90,8 +97,13 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
90 | ret = btrfs_cow_block(trans, root, next, path->nodes[*level], | 97 | ret = btrfs_cow_block(trans, root, next, path->nodes[*level], |
91 | path->slots[*level], &next); | 98 | path->slots[*level], &next); |
92 | BUG_ON(ret); | 99 | BUG_ON(ret); |
93 | ret = btrfs_realloc_node(trans, root, next, cache_only); | 100 | ret = btrfs_realloc_node(trans, root, next, cache_only, |
101 | last_ret); | ||
94 | BUG_ON(ret); | 102 | BUG_ON(ret); |
103 | |||
104 | if (is_extent) | ||
105 | btrfs_extent_post_op(trans, root); | ||
106 | |||
95 | WARN_ON(*level <= 0); | 107 | WARN_ON(*level <= 0); |
96 | if (path->nodes[*level-1]) | 108 | if (path->nodes[*level-1]) |
97 | btrfs_block_release(root, path->nodes[*level-1]); | 109 | btrfs_block_release(root, path->nodes[*level-1]); |
@@ -148,10 +160,14 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
148 | int level; | 160 | int level; |
149 | int orig_level; | 161 | int orig_level; |
150 | int i; | 162 | int i; |
163 | int is_extent = 0; | ||
164 | u64 last_ret = 0; | ||
165 | |||
166 | if (root->fs_info->extent_root == root) | ||
167 | is_extent = 1; | ||
151 | 168 | ||
152 | if (root->ref_cows == 0) { | 169 | if (root->ref_cows == 0 && !is_extent) |
153 | goto out; | 170 | goto out; |
154 | } | ||
155 | path = btrfs_alloc_path(); | 171 | path = btrfs_alloc_path(); |
156 | if (!path) | 172 | if (!path) |
157 | return -ENOMEM; | 173 | return -ENOMEM; |
@@ -165,16 +181,21 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
165 | get_bh(root->node); | 181 | get_bh(root->node); |
166 | ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); | 182 | ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); |
167 | BUG_ON(ret); | 183 | BUG_ON(ret); |
168 | ret = btrfs_realloc_node(trans, root, root->node, cache_only); | 184 | ret = btrfs_realloc_node(trans, root, root->node, cache_only, |
185 | &last_ret); | ||
169 | BUG_ON(ret); | 186 | BUG_ON(ret); |
170 | path->nodes[level] = root->node; | 187 | path->nodes[level] = root->node; |
171 | path->slots[level] = 0; | 188 | path->slots[level] = 0; |
189 | if (is_extent) | ||
190 | btrfs_extent_post_op(trans, root); | ||
172 | } else { | 191 | } else { |
173 | level = root->defrag_level; | 192 | level = root->defrag_level; |
174 | path->lowest_level = level; | 193 | path->lowest_level = level; |
175 | wret = btrfs_search_slot(trans, root, &root->defrag_progress, | 194 | wret = btrfs_search_slot(trans, root, &root->defrag_progress, |
176 | path, 0, 1); | 195 | path, 0, 1); |
177 | 196 | ||
197 | if (is_extent) | ||
198 | btrfs_extent_post_op(trans, root); | ||
178 | if (wret < 0) { | 199 | if (wret < 0) { |
179 | ret = wret; | 200 | ret = wret; |
180 | goto out; | 201 | goto out; |
@@ -188,7 +209,8 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
188 | } | 209 | } |
189 | 210 | ||
190 | while(1) { | 211 | while(1) { |
191 | wret = defrag_walk_down(trans, root, path, &level, cache_only); | 212 | wret = defrag_walk_down(trans, root, path, &level, cache_only, |
213 | &last_ret); | ||
192 | if (wret > 0) | 214 | if (wret > 0) |
193 | break; | 215 | break; |
194 | if (wret < 0) | 216 | if (wret < 0) |