diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-06-25 16:01:31 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:03 -0400 |
commit | e7a84565bcdb239caad29ccbe559ef978090ac7e (patch) | |
tree | aaeba005e713cde2030c27451d98847accff116d /fs/btrfs/tree-defrag.c | |
parent | a74a4b97b61beede185b4b3ad359d7d378b0d312 (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.c | 239 |
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" | |
25 | static 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 | |||
46 | static 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]); | ||
130 | out: | ||
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 | |||
138 | static 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 | ||
168 | int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | 26 | int 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 | |||
263 | out: | 115 | out: |
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) { |