aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-10-15 16:17:34 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:56 -0400
commit6b80053d02be41886344b5007d04e345311ec0b5 (patch)
treec935b3f2f4a582697167c52f57b0985137a95206 /fs/btrfs
parent09e71a326341f40111400c88aaf0498ef622824b (diff)
Btrfs: Add back the online defragging code
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c177
-rw-r--r--fs/btrfs/disk-io.c60
-rw-r--r--fs/btrfs/disk-io.h7
-rw-r--r--fs/btrfs/extent-tree.c8
-rw-r--r--fs/btrfs/extent_map.h2
-rw-r--r--fs/btrfs/transaction.c4
-rw-r--r--fs/btrfs/tree-defrag.c14
7 files changed, 166 insertions, 106 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 34de83630ae9..08ddf1873ab1 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -155,55 +155,49 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
155 return ret; 155 return ret;
156} 156}
157 157
158#if 0 158static int close_blocks(u64 blocknr, u64 other, u32 blocksize)
159static int close_blocks(u64 blocknr, u64 other)
160{ 159{
161 if (blocknr < other && other - blocknr < 8) 160 if (blocknr < other && other - (blocknr + blocksize) < 32768)
162 return 1; 161 return 1;
163 if (blocknr > other && blocknr - other < 8) 162 if (blocknr > other && blocknr - (other + blocksize) < 32768)
164 return 1; 163 return 1;
165 return 0; 164 return 0;
166} 165}
167 166
168static int should_defrag_leaf(struct extent_buffer *eb) 167static int should_defrag_leaf(struct extent_buffer *leaf)
169{ 168{
170 return 0; 169 struct btrfs_key key;
171 struct btrfs_leaf *leaf = btrfs_buffer_leaf(eb);
172 struct btrfs_disk_key *key;
173 u32 nritems; 170 u32 nritems;
174 171
175 if (buffer_defrag(bh)) 172 if (btrfs_buffer_defrag(leaf))
176 return 1; 173 return 1;
177 174
178 nritems = btrfs_header_nritems(&leaf->header); 175 nritems = btrfs_header_nritems(leaf);
179 if (nritems == 0) 176 if (nritems == 0)
180 return 0; 177 return 0;
181 178
182 key = &leaf->items[0].key; 179 btrfs_item_key_to_cpu(leaf, &key, 0);
183 if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY) 180 if (key.type == BTRFS_DIR_ITEM_KEY)
184 return 1; 181 return 1;
185 182
186 key = &leaf->items[nritems-1].key; 183
187 if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY) 184 btrfs_item_key_to_cpu(leaf, &key, nritems - 1);
185 if (key.type == BTRFS_DIR_ITEM_KEY)
188 return 1; 186 return 1;
189 if (nritems > 4) { 187 if (nritems > 4) {
190 key = &leaf->items[nritems/2].key; 188 btrfs_item_key_to_cpu(leaf, &key, nritems / 2);
191 if (btrfs_disk_key_type(key) == BTRFS_DIR_ITEM_KEY) 189 if (key.type == BTRFS_DIR_ITEM_KEY)
192 return 1; 190 return 1;
193 } 191 }
194 return 0; 192 return 0;
195} 193}
196#endif
197 194
198int btrfs_realloc_node(struct btrfs_trans_handle *trans, 195int btrfs_realloc_node(struct btrfs_trans_handle *trans,
199 struct btrfs_root *root, struct extent_buffer *parent, 196 struct btrfs_root *root, struct extent_buffer *parent,
200 int cache_only, u64 *last_ret) 197 int cache_only, u64 *last_ret)
201{ 198{
202 return 0; 199 struct extent_buffer *cur;
203#if 0 200 struct extent_buffer *tmp;
204 struct btrfs_node *parent_node;
205 struct extent_buffer *cur_eb;
206 struct extent_buffer *tmp_eb;
207 u64 blocknr; 201 u64 blocknr;
208 u64 search_start = *last_ret; 202 u64 search_start = *last_ret;
209 u64 last_block = 0; 203 u64 last_block = 0;
@@ -214,6 +208,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
214 int i; 208 int i;
215 int err = 0; 209 int err = 0;
216 int parent_level; 210 int parent_level;
211 int uptodate;
212 u32 blocksize;
217 213
218 if (trans->transaction != root->fs_info->running_transaction) { 214 if (trans->transaction != root->fs_info->running_transaction) {
219 printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, 215 printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid,
@@ -225,12 +221,12 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
225 root->fs_info->generation); 221 root->fs_info->generation);
226 WARN_ON(1); 222 WARN_ON(1);
227 } 223 }
228 if (buffer_defrag_done(parent)) 224 if (btrfs_buffer_defrag_done(parent))
229 return 0; 225 return 0;
230 226
231 parent_node = btrfs_buffer_node(parent); 227 parent_nritems = btrfs_header_nritems(parent);
232 parent_nritems = btrfs_header_nritems(&parent_node->header); 228 parent_level = btrfs_header_level(parent);
233 parent_level = btrfs_header_level(&parent_node->header); 229 blocksize = btrfs_level_size(root, parent_level - 1);
234 230
235 start_slot = 0; 231 start_slot = 0;
236 end_slot = parent_nritems; 232 end_slot = parent_nritems;
@@ -240,56 +236,60 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
240 236
241 for (i = start_slot; i < end_slot; i++) { 237 for (i = start_slot; i < end_slot; i++) {
242 int close = 1; 238 int close = 1;
243 blocknr = btrfs_node_blockptr(parent_node, i); 239 blocknr = btrfs_node_blockptr(parent, i);
244 if (last_block == 0) 240 if (last_block == 0)
245 last_block = blocknr; 241 last_block = blocknr;
246 if (i > 0) { 242 if (i > 0) {
247 other = btrfs_node_blockptr(parent_node, i - 1); 243 other = btrfs_node_blockptr(parent, i - 1);
248 close = close_blocks(blocknr, other); 244 close = close_blocks(blocknr, other, blocksize);
249 } 245 }
250 if (close && i < end_slot - 1) { 246 if (close && i < end_slot - 1) {
251 other = btrfs_node_blockptr(parent_node, i + 1); 247 other = btrfs_node_blockptr(parent, i + 1);
252 close = close_blocks(blocknr, other); 248 close = close_blocks(blocknr, other, blocksize);
253 } 249 }
254 if (close) { 250 if (close) {
255 last_block = blocknr; 251 last_block = blocknr;
256 continue; 252 continue;
257 } 253 }
258 254
259 cur_bh = btrfs_find_tree_block(root, blocknr); 255 cur = btrfs_find_tree_block(root, blocknr, blocksize);
260 if (!cur_bh || !buffer_uptodate(cur_bh) || 256 if (cur)
261 buffer_locked(cur_bh) || 257 uptodate = btrfs_buffer_uptodate(cur);
262 (parent_level != 1 && !buffer_defrag(cur_bh)) || 258 else
263 (parent_level == 1 && !should_defrag_leaf(cur_bh))) { 259 uptodate = 0;
260 if (!cur || !uptodate ||
261 (parent_level != 1 && !btrfs_buffer_defrag(cur)) ||
262 (parent_level == 1 && !should_defrag_leaf(cur))) {
264 if (cache_only) { 263 if (cache_only) {
265 brelse(cur_bh); 264 free_extent_buffer(cur);
266 continue; 265 continue;
267 } 266 }
268 if (!cur_bh || !buffer_uptodate(cur_bh) || 267 if (!cur) {
269 buffer_locked(cur_bh)) { 268 cur = read_tree_block(root, blocknr,
270 brelse(cur_bh); 269 blocksize);
271 cur_bh = read_tree_block(root, blocknr); 270 } else if (!uptodate) {
271 btrfs_read_buffer(cur);
272 } 272 }
273 } 273 }
274 if (search_start == 0) 274 if (search_start == 0)
275 search_start = last_block & ~((u64)65535); 275 search_start = last_block;
276 276
277 err = __btrfs_cow_block(trans, root, cur_bh, parent, i, 277 err = __btrfs_cow_block(trans, root, cur, parent, i,
278 &tmp_bh, search_start, 278 &tmp, search_start,
279 min(8, end_slot - i)); 279 min(16 * blocksize,
280 (end_slot - i) * blocksize));
280 if (err) { 281 if (err) {
281 brelse(cur_bh); 282 free_extent_buffer(cur);
282 break; 283 break;
283 } 284 }
284 search_start = bh_blocknr(tmp_bh); 285 search_start = tmp->start;
285 *last_ret = search_start; 286 *last_ret = search_start;
286 if (parent_level == 1) 287 if (parent_level == 1)
287 clear_buffer_defrag(tmp_bh); 288 btrfs_clear_buffer_defrag(tmp);
288 set_buffer_defrag_done(tmp_bh); 289 btrfs_set_buffer_defrag_done(tmp);
289 brelse(tmp_bh); 290 free_extent_buffer(tmp);
290 } 291 }
291 return err; 292 return err;
292#endif
293} 293}
294 294
295/* 295/*
@@ -892,22 +892,17 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
892static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, 892static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
893 int level, int slot) 893 int level, int slot)
894{ 894{
895 return;
896#if 0
897 struct extent_buffer *node; 895 struct extent_buffer *node;
898 int i;
899 u32 nritems; 896 u32 nritems;
900 u64 bytenr;
901 u64 search; 897 u64 search;
902 u64 cluster_start; 898 u64 lowest_read;
903 int ret; 899 u64 highest_read;
904 int nread = 0; 900 u64 nread = 0;
905 int direction = path->reada; 901 int direction = path->reada;
906 int level;
907 struct radix_tree_root found;
908 unsigned long gang[8];
909 struct extent_buffer *eb; 902 struct extent_buffer *eb;
910 903 u32 nr;
904 u32 blocksize;
905 u32 nscan = 0;
911 906
912 if (level == 0) 907 if (level == 0)
913 return; 908 return;
@@ -917,42 +912,46 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
917 912
918 node = path->nodes[level]; 913 node = path->nodes[level];
919 search = btrfs_node_blockptr(node, slot); 914 search = btrfs_node_blockptr(node, slot);
920 eb = btrfs_find_tree_block(root, search); 915 blocksize = btrfs_level_size(root, level - 1);
916 eb = btrfs_find_tree_block(root, search, blocksize);
921 if (eb) { 917 if (eb) {
922 free_extent_buffer(eb); 918 free_extent_buffer(eb);
923 return; 919 return;
924 } 920 }
925 921
926 init_bit_radix(&found); 922 highest_read = search;
923 lowest_read = search;
924
927 nritems = btrfs_header_nritems(node); 925 nritems = btrfs_header_nritems(node);
928 level = btrfs_header_level(node) - 1; 926 nr = slot;
929 for (i = slot; i < nritems; i++) {
930 bytenr = btrfs_node_blockptr(node, i);
931 set_radix_bit(&found, blocknr);
932 }
933 if (direction > 0) {
934 cluster_start = search - 4;
935 if (cluster_start > search)
936 cluster_start = 0;
937 } else
938 cluster_start = search + 4;
939 while(1) { 927 while(1) {
940 ret = find_first_radix_bit(&found, gang, 0, ARRAY_SIZE(gang)); 928 if (direction < 0) {
941 if (!ret) 929 if (nr == 0)
942 break; 930 break;
943 for (i = 0; i < ret; i++) { 931 nr--;
944 blocknr = gang[i]; 932 } else if (direction > 0) {
945 clear_radix_bit(&found, blocknr); 933 nr++;
946 if (path->reada == 1 && nread > 16) 934 if (nr >= nritems)
947 continue; 935 break;
948 if (close_blocks(cluster_start, blocknr)) {
949 readahead_tree_block(root, blocknr);
950 nread++;
951 cluster_start = blocknr;
952 }
953 } 936 }
937 search = btrfs_node_blockptr(node, nr);
938 if ((search >= lowest_read && search <= highest_read) ||
939 (search < lowest_read && lowest_read - search <= 32768) ||
940 (search > highest_read && search - highest_read <= 32768)) {
941 readahead_tree_block(root, search, blocksize);
942 nread += blocksize;
943 }
944 nscan++;
945 if (path->reada < 2 && (nread > (256 * 1024) || nscan > 32))
946 break;
947 if(nread > (1024 * 1024) || nscan > 128)
948 break;
949
950 if (search < lowest_read)
951 lowest_read = search;
952 if (search > highest_read)
953 highest_read = search;
954 } 954 }
955#endif
956} 955}
957/* 956/*
958 * look for key in the tree. path is filled in with nodes along the way 957 * look for key in the tree. path is filled in with nodes along the way
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0636f79672e9..8e606e6658aa 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -678,3 +678,63 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
678 balance_dirty_pages_ratelimited_nr( 678 balance_dirty_pages_ratelimited_nr(
679 root->fs_info->btree_inode->i_mapping, nr); 679 root->fs_info->btree_inode->i_mapping, nr);
680} 680}
681
682void btrfs_set_buffer_defrag(struct extent_buffer *buf)
683{
684 struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
685 struct inode *btree_inode = root->fs_info->btree_inode;
686 set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
687 buf->start + buf->len - 1, EXTENT_DEFRAG, GFP_NOFS);
688}
689
690void btrfs_set_buffer_defrag_done(struct extent_buffer *buf)
691{
692 struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
693 struct inode *btree_inode = root->fs_info->btree_inode;
694 set_extent_bits(&BTRFS_I(btree_inode)->extent_tree, buf->start,
695 buf->start + buf->len - 1, EXTENT_DEFRAG_DONE,
696 GFP_NOFS);
697}
698
699int btrfs_buffer_defrag(struct extent_buffer *buf)
700{
701 struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
702 struct inode *btree_inode = root->fs_info->btree_inode;
703 return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
704 buf->start, buf->start + buf->len - 1, EXTENT_DEFRAG, 0);
705}
706
707int btrfs_buffer_defrag_done(struct extent_buffer *buf)
708{
709 struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
710 struct inode *btree_inode = root->fs_info->btree_inode;
711 return test_range_bit(&BTRFS_I(btree_inode)->extent_tree,
712 buf->start, buf->start + buf->len - 1,
713 EXTENT_DEFRAG_DONE, 0);
714}
715
716int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf)
717{
718 struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
719 struct inode *btree_inode = root->fs_info->btree_inode;
720 return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
721 buf->start, buf->start + buf->len - 1,
722 EXTENT_DEFRAG_DONE, GFP_NOFS);
723}
724
725int btrfs_clear_buffer_defrag(struct extent_buffer *buf)
726{
727 struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
728 struct inode *btree_inode = root->fs_info->btree_inode;
729 return clear_extent_bits(&BTRFS_I(btree_inode)->extent_tree,
730 buf->start, buf->start + buf->len - 1,
731 EXTENT_DEFRAG, GFP_NOFS);
732}
733
734int btrfs_read_buffer(struct extent_buffer *buf)
735{
736 struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
737 struct inode *btree_inode = root->fs_info->btree_inode;
738 return read_extent_buffer_pages(&BTRFS_I(btree_inode)->extent_tree,
739 buf, 1);
740}
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index fd4db5f810cf..190b07bc642b 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -51,4 +51,11 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf);
51int btrfs_set_buffer_uptodate(struct extent_buffer *buf); 51int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
52int wait_on_tree_block_writeback(struct btrfs_root *root, 52int wait_on_tree_block_writeback(struct btrfs_root *root,
53 struct extent_buffer *buf); 53 struct extent_buffer *buf);
54void btrfs_set_buffer_defrag(struct extent_buffer *buf);
55void btrfs_set_buffer_defrag_done(struct extent_buffer *buf);
56int btrfs_buffer_defrag(struct extent_buffer *buf);
57int btrfs_buffer_defrag_done(struct extent_buffer *buf);
58int btrfs_clear_buffer_defrag(struct extent_buffer *buf);
59int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf);
60int btrfs_read_buffer(struct extent_buffer *buf);
54#endif 61#endif
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 1be8f9f04a13..0b0c947194ae 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1173,13 +1173,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
1173 buf->alloc_addr = (unsigned long)__builtin_return_address(0); 1173 buf->alloc_addr = (unsigned long)__builtin_return_address(0);
1174 set_extent_dirty(&trans->transaction->dirty_pages, buf->start, 1174 set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
1175 buf->start + buf->len - 1, GFP_NOFS); 1175 buf->start + buf->len - 1, GFP_NOFS);
1176 /* 1176 btrfs_set_buffer_defrag(buf);
1177 set_buffer_checked(buf);
1178 set_buffer_defrag(buf);
1179 */
1180 /* FIXME!!!!!!!!!!!!!!!!
1181 set_radix_bit(&trans->transaction->dirty_pages, buf->pages[0]->index);
1182 */
1183 trans->blocks_used++; 1177 trans->blocks_used++;
1184 return buf; 1178 return buf;
1185} 1179}
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index d74a2b3e3b5d..8409b5cbeda7 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -14,6 +14,8 @@
14#define EXTENT_LOCKED (1 << 3) 14#define EXTENT_LOCKED (1 << 3)
15#define EXTENT_NEW (1 << 4) 15#define EXTENT_NEW (1 << 4)
16#define EXTENT_DELALLOC (1 << 5) 16#define EXTENT_DELALLOC (1 << 5)
17#define EXTENT_DEFRAG (1 << 6)
18#define EXTENT_DEFRAG_DONE (1 << 7)
17#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) 19#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
18 20
19 21
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 60f61345a8d0..87456ab74275 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -355,7 +355,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
355 return 0; 355 return 0;
356 356
357 trans = btrfs_start_transaction(root, 1); 357 trans = btrfs_start_transaction(root, 1);
358 while (0) { 358 while (1) {
359 root->defrag_running = 1; 359 root->defrag_running = 1;
360 ret = btrfs_defrag_leaves(trans, root, cacheonly); 360 ret = btrfs_defrag_leaves(trans, root, cacheonly);
361 nr = trans->blocks_used; 361 nr = trans->blocks_used;
@@ -400,7 +400,7 @@ int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info)
400 btrfs_defrag_root(root, 1); 400 btrfs_defrag_root(root, 1);
401 } 401 }
402 } 402 }
403 // btrfs_defrag_root(info->extent_root, 1); 403 btrfs_defrag_root(info->extent_root, 1);
404 return err; 404 return err;
405} 405}
406 406
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
index 3feac2f28628..d23216aa4ab5 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -116,10 +116,10 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
116 } 116 }
117 WARN_ON(*level < 0); 117 WARN_ON(*level < 0);
118 WARN_ON(*level >= BTRFS_MAX_LEVEL); 118 WARN_ON(*level >= BTRFS_MAX_LEVEL);
119#if 0 119
120 clear_buffer_defrag(path->nodes[*level]); 120 btrfs_clear_buffer_defrag(path->nodes[*level]);
121 clear_buffer_defrag_done(path->nodes[*level]); 121 btrfs_clear_buffer_defrag_done(path->nodes[*level]);
122#endif 122
123 free_extent_buffer(path->nodes[*level]); 123 free_extent_buffer(path->nodes[*level]);
124 path->nodes[*level] = NULL; 124 path->nodes[*level] = NULL;
125 *level += 1; 125 *level += 1;
@@ -148,10 +148,8 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans,
148 root->defrag_level = i; 148 root->defrag_level = i;
149 return 0; 149 return 0;
150 } else { 150 } else {
151 /* 151 btrfs_clear_buffer_defrag(path->nodes[*level]);
152 clear_buffer_defrag(path->nodes[*level]); 152 btrfs_clear_buffer_defrag_done(path->nodes[*level]);
153 clear_buffer_defrag_done(path->nodes[*level]);
154 */
155 free_extent_buffer(path->nodes[*level]); 153 free_extent_buffer(path->nodes[*level]);
156 path->nodes[*level] = NULL; 154 path->nodes[*level] = NULL;
157 *level = i + 1; 155 *level = i + 1;