aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/btrfs/ctree.c46
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/extent-tree.c7
-rw-r--r--fs/btrfs/tree-defrag.c239
4 files changed, 93 insertions, 201 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 40f0e0cb804b..7f4cc2b88d09 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -354,7 +354,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
354 struct btrfs_key *progress) 354 struct btrfs_key *progress)
355{ 355{
356 struct extent_buffer *cur; 356 struct extent_buffer *cur;
357 struct extent_buffer *tmp;
358 u64 blocknr; 357 u64 blocknr;
359 u64 gen; 358 u64 gen;
360 u64 search_start = *last_ret; 359 u64 search_start = *last_ret;
@@ -370,9 +369,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
370 int progress_passed = 0; 369 int progress_passed = 0;
371 struct btrfs_disk_key disk_key; 370 struct btrfs_disk_key disk_key;
372 371
373 /* FIXME this code needs locking */
374 return 0;
375
376 parent_level = btrfs_header_level(parent); 372 parent_level = btrfs_header_level(parent);
377 if (cache_only && parent_level != 1) 373 if (cache_only && parent_level != 1)
378 return 0; 374 return 0;
@@ -454,20 +450,23 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
454 if (search_start == 0) 450 if (search_start == 0)
455 search_start = last_block; 451 search_start = last_block;
456 452
453 btrfs_tree_lock(cur);
457 err = __btrfs_cow_block(trans, root, cur, parent, i, 454 err = __btrfs_cow_block(trans, root, cur, parent, i,
458 &tmp, search_start, 455 &cur, search_start,
459 min(16 * blocksize, 456 min(16 * blocksize,
460 (end_slot - i) * blocksize)); 457 (end_slot - i) * blocksize));
461 if (err) { 458 if (err) {
459 btrfs_tree_unlock(cur);
462 free_extent_buffer(cur); 460 free_extent_buffer(cur);
463 break; 461 break;
464 } 462 }
465 search_start = tmp->start; 463 search_start = cur->start;
466 last_block = tmp->start; 464 last_block = cur->start;
467 *last_ret = search_start; 465 *last_ret = search_start;
468 if (parent_level == 1) 466 if (parent_level == 1)
469 btrfs_clear_buffer_defrag(tmp); 467 btrfs_clear_buffer_defrag(cur);
470 free_extent_buffer(tmp); 468 btrfs_tree_unlock(cur);
469 free_extent_buffer(cur);
471 } 470 }
472 if (parent->map_token) { 471 if (parent->map_token) {
473 unmap_extent_buffer(parent, parent->map_token, 472 unmap_extent_buffer(parent, parent->map_token,
@@ -2970,6 +2969,35 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
2970 return 1; 2969 return 1;
2971} 2970}
2972 2971
2972int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
2973 struct btrfs_key *key, int lowest_level)
2974{
2975 int level = lowest_level;
2976 int slot;
2977 struct extent_buffer *c;
2978
2979 while(level < BTRFS_MAX_LEVEL) {
2980 if (!path->nodes[level])
2981 return 1;
2982
2983 slot = path->slots[level] + 1;
2984 c = path->nodes[level];
2985 if (slot >= btrfs_header_nritems(c)) {
2986 level++;
2987 if (level == BTRFS_MAX_LEVEL) {
2988 return 1;
2989 }
2990 continue;
2991 }
2992 if (level == 0)
2993 btrfs_item_key_to_cpu(c, key, slot);
2994 else
2995 btrfs_node_key_to_cpu(c, key, slot);
2996 return 0;
2997 }
2998 return 1;
2999}
3000
2973/* 3001/*
2974 * search the tree again to find a leaf with greater keys 3002 * search the tree again to find a leaf with greater keys
2975 * returns 0 if it found something or 1 if there are no greater leaves. 3003 * returns 0 if it found something or 1 if there are no greater leaves.
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 244fe86bcc55..ca8e6f15859e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1411,6 +1411,8 @@ int btrfs_previous_item(struct btrfs_root *root,
1411 1411
1412struct extent_buffer *btrfs_root_node(struct btrfs_root *root); 1412struct extent_buffer *btrfs_root_node(struct btrfs_root *root);
1413struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root); 1413struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root);
1414int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
1415 struct btrfs_key *key, int lowest_level);
1414 1416
1415int btrfs_cow_block(struct btrfs_trans_handle *trans, 1417int btrfs_cow_block(struct btrfs_trans_handle *trans,
1416 struct btrfs_root *root, struct extent_buffer *buf, 1418 struct btrfs_root *root, struct extent_buffer *buf,
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 89cc4f611869..a9b3a25a45b7 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2201,6 +2201,7 @@ int drop_snap_lookup_refcount(struct btrfs_root *root, u64 start, u64 len,
2201{ 2201{
2202 mutex_unlock(&root->fs_info->alloc_mutex); 2202 mutex_unlock(&root->fs_info->alloc_mutex);
2203 lookup_extent_ref(NULL, root, start, len, refs); 2203 lookup_extent_ref(NULL, root, start, len, refs);
2204 cond_resched();
2204 mutex_lock(&root->fs_info->alloc_mutex); 2205 mutex_lock(&root->fs_info->alloc_mutex);
2205 return lookup_extent_ref(NULL, root, start, len, refs); 2206 return lookup_extent_ref(NULL, root, start, len, refs);
2206} 2207}
@@ -2280,6 +2281,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
2280 2281
2281 next = read_tree_block(root, bytenr, blocksize, 2282 next = read_tree_block(root, bytenr, blocksize,
2282 ptr_gen); 2283 ptr_gen);
2284 cond_resched();
2283 mutex_lock(&root->fs_info->alloc_mutex); 2285 mutex_lock(&root->fs_info->alloc_mutex);
2284 2286
2285 /* we've dropped the lock, double check */ 2287 /* we've dropped the lock, double check */
@@ -2329,6 +2331,7 @@ out:
2329 *level += 1; 2331 *level += 1;
2330 BUG_ON(ret); 2332 BUG_ON(ret);
2331 mutex_unlock(&root->fs_info->alloc_mutex); 2333 mutex_unlock(&root->fs_info->alloc_mutex);
2334 cond_resched();
2332 return 0; 2335 return 0;
2333} 2336}
2334 2337
@@ -2448,6 +2451,10 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
2448 break; 2451 break;
2449 if (wret < 0) 2452 if (wret < 0)
2450 ret = wret; 2453 ret = wret;
2454 if (trans->transaction->in_commit) {
2455 ret = -EAGAIN;
2456 break;
2457 }
2451 } 2458 }
2452 for (i = 0; i <= orig_level; i++) { 2459 for (i = 0; i <= orig_level; i++) {
2453 if (path->nodes[i]) { 2460 if (path->nodes[i]) {
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) {