diff options
Diffstat (limited to 'fs/btrfs/tree-defrag.c')
-rw-r--r-- | fs/btrfs/tree-defrag.c | 58 |
1 files changed, 32 insertions, 26 deletions
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index 420597127ed1..daf019afa0a1 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c | |||
@@ -23,14 +23,14 @@ | |||
23 | #include "transaction.h" | 23 | #include "transaction.h" |
24 | 24 | ||
25 | static void reada_defrag(struct btrfs_root *root, | 25 | static void reada_defrag(struct btrfs_root *root, |
26 | struct btrfs_node *node) | 26 | struct extent_buffer *node) |
27 | { | 27 | { |
28 | int i; | 28 | int i; |
29 | u32 nritems; | 29 | u32 nritems; |
30 | u64 blocknr; | 30 | u64 blocknr; |
31 | int ret; | 31 | int ret; |
32 | 32 | ||
33 | nritems = btrfs_header_nritems(&node->header); | 33 | nritems = btrfs_header_nritems(node); |
34 | for (i = 0; i < nritems; i++) { | 34 | for (i = 0; i < nritems; i++) { |
35 | blocknr = btrfs_node_blockptr(node, i); | 35 | blocknr = btrfs_node_blockptr(node, i); |
36 | ret = readahead_tree_block(root, blocknr); | 36 | ret = readahead_tree_block(root, blocknr); |
@@ -44,8 +44,8 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
44 | struct btrfs_path *path, int *level, | 44 | struct btrfs_path *path, int *level, |
45 | int cache_only, u64 *last_ret) | 45 | int cache_only, u64 *last_ret) |
46 | { | 46 | { |
47 | struct buffer_head *next; | 47 | struct extent_buffer *next; |
48 | struct buffer_head *cur; | 48 | struct extent_buffer *cur; |
49 | u64 blocknr; | 49 | u64 blocknr; |
50 | int ret = 0; | 50 | int ret = 0; |
51 | int is_extent = 0; | 51 | int is_extent = 0; |
@@ -62,13 +62,13 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
62 | cur = path->nodes[*level]; | 62 | cur = path->nodes[*level]; |
63 | 63 | ||
64 | if (!cache_only && *level > 1 && path->slots[*level] == 0) | 64 | if (!cache_only && *level > 1 && path->slots[*level] == 0) |
65 | reada_defrag(root, btrfs_buffer_node(cur)); | 65 | reada_defrag(root, cur); |
66 | 66 | ||
67 | if (btrfs_header_level(btrfs_buffer_header(cur)) != *level) | 67 | if (btrfs_header_level(cur) != *level) |
68 | WARN_ON(1); | 68 | WARN_ON(1); |
69 | 69 | ||
70 | if (path->slots[*level] >= | 70 | if (path->slots[*level] >= |
71 | btrfs_header_nritems(btrfs_buffer_header(cur))) | 71 | btrfs_header_nritems(cur)) |
72 | break; | 72 | break; |
73 | 73 | ||
74 | if (*level == 1) { | 74 | if (*level == 1) { |
@@ -80,14 +80,13 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
80 | 80 | ||
81 | break; | 81 | break; |
82 | } | 82 | } |
83 | blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur), | 83 | blocknr = btrfs_node_blockptr(cur, path->slots[*level]); |
84 | path->slots[*level]); | ||
85 | 84 | ||
86 | if (cache_only) { | 85 | if (cache_only) { |
87 | next = btrfs_find_tree_block(root, blocknr); | 86 | next = btrfs_find_tree_block(root, blocknr); |
88 | if (!next || !buffer_uptodate(next) || | 87 | /* FIXME, test for defrag */ |
89 | buffer_locked(next) || !buffer_defrag(next)) { | 88 | if (!next || !btrfs_buffer_uptodate(next)) { |
90 | brelse(next); | 89 | free_extent_buffer(next); |
91 | path->slots[*level]++; | 90 | path->slots[*level]++; |
92 | continue; | 91 | continue; |
93 | } | 92 | } |
@@ -106,16 +105,18 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
106 | 105 | ||
107 | WARN_ON(*level <= 0); | 106 | WARN_ON(*level <= 0); |
108 | if (path->nodes[*level-1]) | 107 | if (path->nodes[*level-1]) |
109 | btrfs_block_release(root, path->nodes[*level-1]); | 108 | free_extent_buffer(path->nodes[*level-1]); |
110 | path->nodes[*level-1] = next; | 109 | path->nodes[*level-1] = next; |
111 | *level = btrfs_header_level(btrfs_buffer_header(next)); | 110 | *level = btrfs_header_level(next); |
112 | path->slots[*level] = 0; | 111 | path->slots[*level] = 0; |
113 | } | 112 | } |
114 | WARN_ON(*level < 0); | 113 | WARN_ON(*level < 0); |
115 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 114 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
115 | #if 0 | ||
116 | clear_buffer_defrag(path->nodes[*level]); | 116 | clear_buffer_defrag(path->nodes[*level]); |
117 | clear_buffer_defrag_done(path->nodes[*level]); | 117 | clear_buffer_defrag_done(path->nodes[*level]); |
118 | btrfs_block_release(root, path->nodes[*level]); | 118 | #endif |
119 | free_extent_buffer(path->nodes[*level]); | ||
119 | path->nodes[*level] = NULL; | 120 | path->nodes[*level] = NULL; |
120 | *level += 1; | 121 | *level += 1; |
121 | WARN_ON(ret); | 122 | WARN_ON(ret); |
@@ -129,24 +130,25 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans, | |||
129 | { | 130 | { |
130 | int i; | 131 | int i; |
131 | int slot; | 132 | int slot; |
132 | struct btrfs_node *node; | 133 | struct extent_buffer *node; |
133 | 134 | ||
134 | for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { | 135 | for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { |
135 | slot = path->slots[i]; | 136 | slot = path->slots[i]; |
136 | if (slot < btrfs_header_nritems( | 137 | if (slot < btrfs_header_nritems(path->nodes[i]) - 1) { |
137 | btrfs_buffer_header(path->nodes[i])) - 1) { | ||
138 | path->slots[i]++; | 138 | path->slots[i]++; |
139 | *level = i; | 139 | *level = i; |
140 | node = btrfs_buffer_node(path->nodes[i]); | 140 | node = path->nodes[i]; |
141 | WARN_ON(i == 0); | 141 | WARN_ON(i == 0); |
142 | btrfs_disk_key_to_cpu(&root->defrag_progress, | 142 | btrfs_node_key_to_cpu(node, &root->defrag_progress, |
143 | &node->ptrs[path->slots[i]].key); | 143 | path->slots[i]); |
144 | root->defrag_level = i; | 144 | root->defrag_level = i; |
145 | return 0; | 145 | return 0; |
146 | } else { | 146 | } else { |
147 | /* | ||
147 | clear_buffer_defrag(path->nodes[*level]); | 148 | clear_buffer_defrag(path->nodes[*level]); |
148 | clear_buffer_defrag_done(path->nodes[*level]); | 149 | clear_buffer_defrag_done(path->nodes[*level]); |
149 | btrfs_block_release(root, path->nodes[*level]); | 150 | */ |
151 | free_extent_buffer(path->nodes[*level]); | ||
150 | path->nodes[*level] = NULL; | 152 | path->nodes[*level] = NULL; |
151 | *level = i + 1; | 153 | *level = i + 1; |
152 | } | 154 | } |
@@ -158,7 +160,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
158 | struct btrfs_root *root, int cache_only) | 160 | struct btrfs_root *root, int cache_only) |
159 | { | 161 | { |
160 | struct btrfs_path *path = NULL; | 162 | struct btrfs_path *path = NULL; |
161 | struct buffer_head *tmp; | 163 | struct extent_buffer *tmp; |
162 | int ret = 0; | 164 | int ret = 0; |
163 | int wret; | 165 | int wret; |
164 | int level; | 166 | int level; |
@@ -172,17 +174,18 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
172 | 174 | ||
173 | if (root->ref_cows == 0 && !is_extent) | 175 | if (root->ref_cows == 0 && !is_extent) |
174 | goto out; | 176 | goto out; |
177 | |||
175 | path = btrfs_alloc_path(); | 178 | path = btrfs_alloc_path(); |
176 | if (!path) | 179 | if (!path) |
177 | return -ENOMEM; | 180 | return -ENOMEM; |
178 | 181 | ||
179 | level = btrfs_header_level(btrfs_buffer_header(root->node)); | 182 | level = btrfs_header_level(root->node); |
180 | orig_level = level; | 183 | orig_level = level; |
181 | if (level == 0) { | 184 | if (level == 0) { |
182 | goto out; | 185 | goto out; |
183 | } | 186 | } |
184 | if (root->defrag_progress.objectid == 0) { | 187 | if (root->defrag_progress.objectid == 0) { |
185 | get_bh(root->node); | 188 | extent_buffer_get(root->node); |
186 | ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); | 189 | ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); |
187 | BUG_ON(ret); | 190 | BUG_ON(ret); |
188 | ret = btrfs_realloc_node(trans, root, root->node, cache_only, | 191 | ret = btrfs_realloc_node(trans, root, root->node, cache_only, |
@@ -200,12 +203,15 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
200 | 203 | ||
201 | if (is_extent) | 204 | if (is_extent) |
202 | btrfs_extent_post_op(trans, root); | 205 | btrfs_extent_post_op(trans, root); |
206 | |||
203 | if (wret < 0) { | 207 | if (wret < 0) { |
204 | ret = wret; | 208 | ret = wret; |
205 | goto out; | 209 | goto out; |
206 | } | 210 | } |
211 | |||
207 | while(level > 0 && !path->nodes[level]) | 212 | while(level > 0 && !path->nodes[level]) |
208 | level--; | 213 | level--; |
214 | |||
209 | if (!path->nodes[level]) { | 215 | if (!path->nodes[level]) { |
210 | ret = 0; | 216 | ret = 0; |
211 | goto out; | 217 | goto out; |
@@ -230,7 +236,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
230 | } | 236 | } |
231 | for (i = 0; i <= orig_level; i++) { | 237 | for (i = 0; i <= orig_level; i++) { |
232 | if (path->nodes[i]) { | 238 | if (path->nodes[i]) { |
233 | btrfs_block_release(root, path->nodes[i]); | 239 | free_extent_buffer(path->nodes[i]); |
234 | path->nodes[i] = 0; | 240 | path->nodes[i] = 0; |
235 | } | 241 | } |
236 | } | 242 | } |