aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-defrag.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-06-25 16:01:31 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:03 -0400
commite7a84565bcdb239caad29ccbe559ef978090ac7e (patch)
treeaaeba005e713cde2030c27451d98847accff116d /fs/btrfs/tree-defrag.c
parenta74a4b97b61beede185b4b3ad359d7d378b0d312 (diff)
Btrfs: Add btree locking to the tree defragmentation code
The online btree defragger is simplified and rewritten to use standard btree searches instead of a walk up / down mechanism. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/tree-defrag.c')
-rw-r--r--fs/btrfs/tree-defrag.c239
1 files changed, 47 insertions, 192 deletions
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
index fab851d85383..1677e4edaf6f 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -21,167 +21,26 @@
21#include "disk-io.h" 21#include "disk-io.h"
22#include "print-tree.h" 22#include "print-tree.h"
23#include "transaction.h" 23#include "transaction.h"
24 24#include "locking.h"
25static void reada_defrag(struct btrfs_root *root,
26 struct extent_buffer *node)
27{
28 int i;
29 u32 nritems;
30 u64 bytenr;
31 u64 gen;
32 u32 blocksize;
33 int ret;
34
35 blocksize = btrfs_level_size(root, btrfs_header_level(node) - 1);
36 nritems = btrfs_header_nritems(node);
37 for (i = 0; i < nritems; i++) {
38 bytenr = btrfs_node_blockptr(node, i);
39 gen = btrfs_node_ptr_generation(node, i);
40 ret = readahead_tree_block(root, bytenr, blocksize, gen);
41 if (ret)
42 break;
43 }
44}
45
46static int defrag_walk_down(struct btrfs_trans_handle *trans,
47 struct btrfs_root *root,
48 struct btrfs_path *path, int *level,
49 int cache_only, u64 *last_ret)
50{
51 struct extent_buffer *next;
52 struct extent_buffer *cur;
53 u64 bytenr;
54 u64 ptr_gen;
55 int ret = 0;
56 int is_extent = 0;
57
58 WARN_ON(*level < 0);
59 WARN_ON(*level >= BTRFS_MAX_LEVEL);
60
61 if (root->fs_info->extent_root == root)
62 is_extent = 1;
63
64 if (*level == 1 && cache_only && path->nodes[1] &&
65 !btrfs_buffer_defrag(path->nodes[1])) {
66 goto out;
67 }
68 while(*level > 0) {
69 WARN_ON(*level < 0);
70 WARN_ON(*level >= BTRFS_MAX_LEVEL);
71 cur = path->nodes[*level];
72
73 if (!cache_only && *level > 1 && path->slots[*level] == 0)
74 reada_defrag(root, cur);
75
76 if (btrfs_header_level(cur) != *level)
77 WARN_ON(1);
78
79 if (path->slots[*level] >=
80 btrfs_header_nritems(cur))
81 break;
82
83 if (*level == 1) {
84 WARN_ON(btrfs_header_generation(path->nodes[*level]) !=
85 trans->transid);
86 ret = btrfs_realloc_node(trans, root,
87 path->nodes[*level],
88 path->slots[*level],
89 cache_only, last_ret,
90 &root->defrag_progress);
91 if (is_extent)
92 btrfs_extent_post_op(trans, root);
93
94 break;
95 }
96 bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
97 ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
98
99 if (cache_only) {
100 next = btrfs_find_tree_block(root, bytenr,
101 btrfs_level_size(root, *level - 1));
102 if (!next || !btrfs_buffer_uptodate(next, ptr_gen) ||
103 !btrfs_buffer_defrag(next)) {
104 free_extent_buffer(next);
105 path->slots[*level]++;
106 continue;
107 }
108 } else {
109 next = read_tree_block(root, bytenr,
110 btrfs_level_size(root, *level - 1),
111 ptr_gen);
112 }
113 ret = btrfs_cow_block(trans, root, next, path->nodes[*level],
114 path->slots[*level], &next);
115 BUG_ON(ret);
116 if (is_extent)
117 btrfs_extent_post_op(trans, root);
118
119 WARN_ON(*level <= 0);
120 if (path->nodes[*level-1])
121 free_extent_buffer(path->nodes[*level-1]);
122 path->nodes[*level-1] = next;
123 *level = btrfs_header_level(next);
124 path->slots[*level] = 0;
125 }
126 WARN_ON(*level < 0);
127 WARN_ON(*level >= BTRFS_MAX_LEVEL);
128
129 btrfs_clear_buffer_defrag(path->nodes[*level]);
130out:
131 free_extent_buffer(path->nodes[*level]);
132 path->nodes[*level] = NULL;
133 *level += 1;
134 WARN_ON(ret && ret != -EAGAIN);
135 return ret;
136}
137
138static int defrag_walk_up(struct btrfs_trans_handle *trans,
139 struct btrfs_root *root,
140 struct btrfs_path *path, int *level,
141 int cache_only)
142{
143 int i;
144 int slot;
145 struct extent_buffer *node;
146
147 for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
148 slot = path->slots[i];
149 if (slot < btrfs_header_nritems(path->nodes[i]) - 1) {
150 path->slots[i]++;
151 *level = i;
152 node = path->nodes[i];
153 WARN_ON(i == 0);
154 btrfs_node_key_to_cpu(node, &root->defrag_progress,
155 path->slots[i]);
156 root->defrag_level = i;
157 return 0;
158 } else {
159 btrfs_clear_buffer_defrag(path->nodes[*level]);
160 free_extent_buffer(path->nodes[*level]);
161 path->nodes[*level] = NULL;
162 *level = i + 1;
163 }
164 }
165 return 1;
166}
167 25
168int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, 26int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
169 struct btrfs_root *root, int cache_only) 27 struct btrfs_root *root, int cache_only)
170{ 28{
171 struct btrfs_path *path = NULL; 29 struct btrfs_path *path = NULL;
172 struct extent_buffer *tmp; 30 struct btrfs_key key;
173 int ret = 0; 31 int ret = 0;
174 int wret; 32 int wret;
175 int level; 33 int level;
176 int orig_level; 34 int orig_level;
177 int i; 35 int i;
178 int is_extent = 0; 36 int is_extent = 0;
37 int next_key_ret = 0;
179 u64 last_ret = 0; 38 u64 last_ret = 0;
180 39
181 if (root->fs_info->extent_root == root) 40 if (root->fs_info->extent_root == root) {
41 mutex_lock(&root->fs_info->alloc_mutex);
182 is_extent = 1; 42 is_extent = 1;
183 43 }
184 goto out;
185 44
186 if (root->ref_cows == 0 && !is_extent) 45 if (root->ref_cows == 0 && !is_extent)
187 goto out; 46 goto out;
@@ -200,67 +59,63 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
200 goto out; 59 goto out;
201 } 60 }
202 if (root->defrag_progress.objectid == 0) { 61 if (root->defrag_progress.objectid == 0) {
62 struct extent_buffer *root_node;
203 u32 nritems; 63 u32 nritems;
204 64
205 nritems = btrfs_header_nritems(root->node); 65 root_node = btrfs_lock_root_node(root);
66 nritems = btrfs_header_nritems(root_node);
206 root->defrag_max.objectid = 0; 67 root->defrag_max.objectid = 0;
207 /* from above we know this is not a leaf */ 68 /* from above we know this is not a leaf */
208 btrfs_node_key_to_cpu(root->node, &root->defrag_max, 69 btrfs_node_key_to_cpu(root_node, &root->defrag_max,
209 nritems - 1); 70 nritems - 1);
210 extent_buffer_get(root->node); 71 btrfs_tree_unlock(root_node);
211 ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); 72 free_extent_buffer(root_node);
212 BUG_ON(ret); 73 memset(&key, 0, sizeof(key));
213 path->nodes[level] = root->node;
214 path->slots[level] = 0;
215 if (is_extent)
216 btrfs_extent_post_op(trans, root);
217 } else { 74 } else {
218 level = root->defrag_level; 75 memcpy(&key, &root->defrag_progress, sizeof(key));
219 path->lowest_level = level;
220 wret = btrfs_search_slot(trans, root, &root->defrag_progress,
221 path, 0, 1);
222
223 if (is_extent)
224 btrfs_extent_post_op(trans, root);
225
226 if (wret < 0) {
227 ret = wret;
228 goto out;
229 }
230
231 while(level > 0 && !path->nodes[level])
232 level--;
233
234 if (!path->nodes[level]) {
235 ret = 0;
236 goto out;
237 }
238 } 76 }
239 77
240 while(1) { 78 path->lowest_level = 1;
241 wret = defrag_walk_down(trans, root, path, &level, cache_only, 79 path->keep_locks = 1;
242 &last_ret); 80 wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
243 if (wret > 0)
244 break;
245 if (wret < 0)
246 ret = wret;
247 81
248 wret = defrag_walk_up(trans, root, path, &level, cache_only); 82 if (wret < 0) {
249 if (wret > 0) 83 ret = wret;
250 break; 84 goto out;
251 if (wret < 0) 85 }
252 ret = wret; 86 if (!path->nodes[1]) {
253 else 87 ret = 0;
254 ret = -EAGAIN; 88 goto out;
255 break; 89 }
90 path->slots[1] = btrfs_header_nritems(path->nodes[1]);
91 next_key_ret = btrfs_find_next_key(root, path, &key, 1);
92 ret = btrfs_realloc_node(trans, root,
93 path->nodes[1], 0,
94 cache_only, &last_ret,
95 &root->defrag_progress);
96 WARN_ON(ret && ret != -EAGAIN);
97 if (next_key_ret == 0) {
98 memcpy(&root->defrag_progress, &key, sizeof(key));
99 ret = -EAGAIN;
256 } 100 }
257 for (i = 0; i <= orig_level; i++) { 101
102 for (i = 1; i < BTRFS_MAX_LEVEL; i++) {
103 if (path->locks[i]) {
104 btrfs_tree_unlock(path->nodes[i]);
105 path->locks[i] = 0;
106 }
258 if (path->nodes[i]) { 107 if (path->nodes[i]) {
259 free_extent_buffer(path->nodes[i]); 108 free_extent_buffer(path->nodes[i]);
260 path->nodes[i] = NULL; 109 path->nodes[i] = NULL;
261 } 110 }
262 } 111 }
112 if (is_extent)
113 btrfs_extent_post_op(trans, root);
114
263out: 115out:
116 if (is_extent)
117 mutex_unlock(&root->fs_info->alloc_mutex);
118
264 if (path) 119 if (path)
265 btrfs_free_path(path); 120 btrfs_free_path(path);
266 if (ret == -EAGAIN) { 121 if (ret == -EAGAIN) {