diff options
-rw-r--r-- | fs/btrfs/ctree.c | 18 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 4 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 28 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 23 | ||||
-rw-r--r-- | fs/btrfs/super.c | 2 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 91 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 2 | ||||
-rw-r--r-- | fs/btrfs/tree-defrag.c | 36 |
8 files changed, 125 insertions, 79 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index c7e47e77723f..ee1ae00d2827 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -99,7 +99,6 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root | |||
99 | if (ret) | 99 | if (ret) |
100 | return ret; | 100 | return ret; |
101 | } else { | 101 | } else { |
102 | WARN_ON(!root->ref_cows); | ||
103 | clean_tree_block(trans, root, buf); | 102 | clean_tree_block(trans, root, buf); |
104 | } | 103 | } |
105 | 104 | ||
@@ -162,13 +161,14 @@ static int close_blocks(u64 blocknr, u64 other) | |||
162 | 161 | ||
163 | int btrfs_realloc_node(struct btrfs_trans_handle *trans, | 162 | int btrfs_realloc_node(struct btrfs_trans_handle *trans, |
164 | struct btrfs_root *root, struct buffer_head *parent, | 163 | struct btrfs_root *root, struct buffer_head *parent, |
165 | int cache_only) | 164 | int cache_only, u64 *last_ret) |
166 | { | 165 | { |
167 | struct btrfs_node *parent_node; | 166 | struct btrfs_node *parent_node; |
168 | struct buffer_head *cur_bh; | 167 | struct buffer_head *cur_bh; |
169 | struct buffer_head *tmp_bh; | 168 | struct buffer_head *tmp_bh; |
170 | u64 blocknr; | 169 | u64 blocknr; |
171 | u64 search_start = 0; | 170 | u64 search_start = *last_ret; |
171 | u64 last_block = 0; | ||
172 | u64 other; | 172 | u64 other; |
173 | u32 parent_nritems; | 173 | u32 parent_nritems; |
174 | int start_slot; | 174 | int start_slot; |
@@ -198,6 +198,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
198 | for (i = start_slot; i < end_slot; i++) { | 198 | for (i = start_slot; i < end_slot; i++) { |
199 | int close = 1; | 199 | int close = 1; |
200 | blocknr = btrfs_node_blockptr(parent_node, i); | 200 | blocknr = btrfs_node_blockptr(parent_node, i); |
201 | if (last_block == 0) | ||
202 | last_block = blocknr; | ||
201 | if (i > 0) { | 203 | if (i > 0) { |
202 | other = btrfs_node_blockptr(parent_node, i - 1); | 204 | other = btrfs_node_blockptr(parent_node, i - 1); |
203 | close = close_blocks(blocknr, other); | 205 | close = close_blocks(blocknr, other); |
@@ -206,8 +208,10 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
206 | other = btrfs_node_blockptr(parent_node, i + 1); | 208 | other = btrfs_node_blockptr(parent_node, i + 1); |
207 | close = close_blocks(blocknr, other); | 209 | close = close_blocks(blocknr, other); |
208 | } | 210 | } |
209 | if (close) | 211 | if (close) { |
212 | last_block = blocknr; | ||
210 | continue; | 213 | continue; |
214 | } | ||
211 | 215 | ||
212 | cur_bh = btrfs_find_tree_block(root, blocknr); | 216 | cur_bh = btrfs_find_tree_block(root, blocknr); |
213 | if (!cur_bh || !buffer_uptodate(cur_bh) || | 217 | if (!cur_bh || !buffer_uptodate(cur_bh) || |
@@ -219,9 +223,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
219 | brelse(cur_bh); | 223 | brelse(cur_bh); |
220 | cur_bh = read_tree_block(root, blocknr); | 224 | cur_bh = read_tree_block(root, blocknr); |
221 | } | 225 | } |
222 | if (search_start == 0) { | 226 | if (search_start == 0) |
223 | search_start = bh_blocknr(cur_bh) & ~((u64)65535); | 227 | search_start = last_block & ~((u64)65535); |
224 | } | 228 | |
225 | err = __btrfs_cow_block(trans, root, cur_bh, parent, i, | 229 | err = __btrfs_cow_block(trans, root, cur_bh, parent, i, |
226 | &tmp_bh, search_start, | 230 | &tmp_bh, search_start, |
227 | min(8, end_slot - i)); | 231 | min(8, end_slot - i)); |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 59e09e37ab93..d3cd564b3b3f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1019,6 +1019,8 @@ static inline void btrfs_memmove(struct btrfs_root *root, | |||
1019 | btrfs_item_offset((leaf)->items + (slot)))) | 1019 | btrfs_item_offset((leaf)->items + (slot)))) |
1020 | 1020 | ||
1021 | /* extent-tree.c */ | 1021 | /* extent-tree.c */ |
1022 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, | ||
1023 | struct btrfs_root *root); | ||
1022 | int btrfs_copy_pinned(struct btrfs_root *root, struct radix_tree_root *copy); | 1024 | int btrfs_copy_pinned(struct btrfs_root *root, struct radix_tree_root *copy); |
1023 | struct btrfs_block_group_cache *btrfs_lookup_block_group(struct | 1025 | struct btrfs_block_group_cache *btrfs_lookup_block_group(struct |
1024 | btrfs_fs_info *info, | 1026 | btrfs_fs_info *info, |
@@ -1066,7 +1068,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1066 | ins_len, int cow); | 1068 | ins_len, int cow); |
1067 | int btrfs_realloc_node(struct btrfs_trans_handle *trans, | 1069 | int btrfs_realloc_node(struct btrfs_trans_handle *trans, |
1068 | struct btrfs_root *root, struct buffer_head *parent, | 1070 | struct btrfs_root *root, struct buffer_head *parent, |
1069 | int cache_only); | 1071 | int cache_only, u64 *last_ret); |
1070 | void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p); | 1072 | void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p); |
1071 | struct btrfs_path *btrfs_alloc_path(void); | 1073 | struct btrfs_path *btrfs_alloc_path(void); |
1072 | void btrfs_free_path(struct btrfs_path *p); | 1074 | void btrfs_free_path(struct btrfs_path *p); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 120c448f58f8..3418bb62b996 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -396,6 +396,14 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | |||
396 | return 0; | 396 | return 0; |
397 | } | 397 | } |
398 | 398 | ||
399 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, | ||
400 | struct btrfs_root *root) | ||
401 | { | ||
402 | finish_current_insert(trans, root->fs_info->extent_root); | ||
403 | del_pending_extents(trans, root->fs_info->extent_root); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
399 | static int lookup_extent_ref(struct btrfs_trans_handle *trans, | 407 | static int lookup_extent_ref(struct btrfs_trans_handle *trans, |
400 | struct btrfs_root *root, u64 blocknr, | 408 | struct btrfs_root *root, u64 blocknr, |
401 | u64 num_blocks, u32 *refs) | 409 | u64 num_blocks, u32 *refs) |
@@ -1374,7 +1382,25 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1374 | BUG_ON(ret); | 1382 | BUG_ON(ret); |
1375 | continue; | 1383 | continue; |
1376 | } | 1384 | } |
1377 | next = read_tree_block(root, blocknr); | 1385 | next = btrfs_find_tree_block(root, blocknr); |
1386 | if (!next || !buffer_uptodate(next)) { | ||
1387 | brelse(next); | ||
1388 | mutex_unlock(&root->fs_info->fs_mutex); | ||
1389 | next = read_tree_block(root, blocknr); | ||
1390 | mutex_lock(&root->fs_info->fs_mutex); | ||
1391 | |||
1392 | /* we dropped the lock, check one more time */ | ||
1393 | ret = lookup_extent_ref(trans, root, blocknr, 1, &refs); | ||
1394 | BUG_ON(ret); | ||
1395 | if (refs != 1) { | ||
1396 | path->slots[*level]++; | ||
1397 | brelse(next); | ||
1398 | ret = btrfs_free_extent(trans, root, | ||
1399 | blocknr, 1, 1); | ||
1400 | BUG_ON(ret); | ||
1401 | continue; | ||
1402 | } | ||
1403 | } | ||
1378 | WARN_ON(*level <= 0); | 1404 | WARN_ON(*level <= 0); |
1379 | if (path->nodes[*level-1]) | 1405 | if (path->nodes[*level-1]) |
1380 | btrfs_block_release(root, path->nodes[*level-1]); | 1406 | btrfs_block_release(root, path->nodes[*level-1]); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 12aa043b9f6f..5c05ecbc5726 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2159,9 +2159,7 @@ int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int | |||
2159 | { | 2159 | { |
2160 | struct btrfs_root *root = BTRFS_I(inode)->root; | 2160 | struct btrfs_root *root = BTRFS_I(inode)->root; |
2161 | struct btrfs_ioctl_vol_args vol_args; | 2161 | struct btrfs_ioctl_vol_args vol_args; |
2162 | struct btrfs_trans_handle *trans; | ||
2163 | int ret = 0; | 2162 | int ret = 0; |
2164 | int err; | ||
2165 | struct btrfs_dir_item *di; | 2163 | struct btrfs_dir_item *di; |
2166 | int namelen; | 2164 | int namelen; |
2167 | struct btrfs_path *path; | 2165 | struct btrfs_path *path; |
@@ -2201,25 +2199,8 @@ int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int | |||
2201 | 2199 | ||
2202 | case BTRFS_IOC_DEFRAG: | 2200 | case BTRFS_IOC_DEFRAG: |
2203 | mutex_lock(&root->fs_info->fs_mutex); | 2201 | mutex_lock(&root->fs_info->fs_mutex); |
2204 | trans = btrfs_start_transaction(root, 1); | 2202 | btrfs_defrag_root(root, 0); |
2205 | memset(&root->defrag_progress, 0, | 2203 | btrfs_defrag_root(root->fs_info->extent_root, 0); |
2206 | sizeof(root->defrag_progress)); | ||
2207 | while (1) { | ||
2208 | root->defrag_running = 1; | ||
2209 | err = btrfs_defrag_leaves(trans, root, 0); | ||
2210 | |||
2211 | btrfs_end_transaction(trans, root); | ||
2212 | mutex_unlock(&root->fs_info->fs_mutex); | ||
2213 | |||
2214 | btrfs_btree_balance_dirty(root); | ||
2215 | |||
2216 | mutex_lock(&root->fs_info->fs_mutex); | ||
2217 | trans = btrfs_start_transaction(root, 1); | ||
2218 | if (err != -EAGAIN) | ||
2219 | break; | ||
2220 | } | ||
2221 | root->defrag_running = 0; | ||
2222 | btrfs_end_transaction(trans, root); | ||
2223 | mutex_unlock(&root->fs_info->fs_mutex); | 2204 | mutex_unlock(&root->fs_info->fs_mutex); |
2224 | ret = 0; | 2205 | ret = 0; |
2225 | break; | 2206 | break; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 2e797d5fb281..74f3de47423c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -121,7 +121,9 @@ static int btrfs_sync_fs(struct super_block *sb, int wait) | |||
121 | filemap_flush(root->fs_info->btree_inode->i_mapping); | 121 | filemap_flush(root->fs_info->btree_inode->i_mapping); |
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | btrfs_clean_old_snapshots(root); | ||
124 | mutex_lock(&root->fs_info->fs_mutex); | 125 | mutex_lock(&root->fs_info->fs_mutex); |
126 | btrfs_defrag_dirty_roots(root->fs_info); | ||
125 | trans = btrfs_start_transaction(root, 1); | 127 | trans = btrfs_start_transaction(root, 1); |
126 | ret = btrfs_commit_transaction(trans, root); | 128 | ret = btrfs_commit_transaction(trans, root); |
127 | sb->s_dirt = 0; | 129 | sb->s_dirt = 0; |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 204337c5ca0f..c9d52dc83e48 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -317,18 +317,47 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
317 | return err; | 317 | return err; |
318 | } | 318 | } |
319 | 319 | ||
320 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | ||
321 | { | ||
322 | struct btrfs_fs_info *info = root->fs_info; | ||
323 | int ret; | ||
324 | struct btrfs_trans_handle *trans; | ||
325 | |||
326 | if (root->defrag_running) | ||
327 | return 0; | ||
328 | |||
329 | trans = btrfs_start_transaction(root, 1); | ||
330 | while (1) { | ||
331 | root->defrag_running = 1; | ||
332 | ret = btrfs_defrag_leaves(trans, root, cacheonly); | ||
333 | btrfs_end_transaction(trans, root); | ||
334 | mutex_unlock(&info->fs_mutex); | ||
335 | |||
336 | btrfs_btree_balance_dirty(root); | ||
337 | cond_resched(); | ||
338 | |||
339 | mutex_lock(&info->fs_mutex); | ||
340 | trans = btrfs_start_transaction(root, 1); | ||
341 | if (ret != -EAGAIN) | ||
342 | break; | ||
343 | } | ||
344 | root->defrag_running = 0; | ||
345 | radix_tree_tag_clear(&info->fs_roots_radix, | ||
346 | (unsigned long)root->root_key.objectid, | ||
347 | BTRFS_ROOT_DEFRAG_TAG); | ||
348 | btrfs_end_transaction(trans, root); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
320 | int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info) | 352 | int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info) |
321 | { | 353 | { |
322 | struct btrfs_root *gang[1]; | 354 | struct btrfs_root *gang[1]; |
323 | struct btrfs_root *root; | 355 | struct btrfs_root *root; |
324 | struct btrfs_root *tree_root = info->tree_root; | ||
325 | struct btrfs_trans_handle *trans; | ||
326 | int i; | 356 | int i; |
327 | int ret; | 357 | int ret; |
328 | int err = 0; | 358 | int err = 0; |
329 | u64 last = 0; | 359 | u64 last = 0; |
330 | 360 | ||
331 | trans = btrfs_start_transaction(tree_root, 1); | ||
332 | while(1) { | 361 | while(1) { |
333 | ret = radix_tree_gang_lookup_tag(&info->fs_roots_radix, | 362 | ret = radix_tree_gang_lookup_tag(&info->fs_roots_radix, |
334 | (void **)gang, last, | 363 | (void **)gang, last, |
@@ -339,37 +368,10 @@ int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info) | |||
339 | for (i = 0; i < ret; i++) { | 368 | for (i = 0; i < ret; i++) { |
340 | root = gang[i]; | 369 | root = gang[i]; |
341 | last = root->root_key.objectid + 1; | 370 | last = root->root_key.objectid + 1; |
342 | radix_tree_tag_clear(&info->fs_roots_radix, | 371 | btrfs_defrag_root(root, 1); |
343 | (unsigned long)root->root_key.objectid, | ||
344 | BTRFS_ROOT_DEFRAG_TAG); | ||
345 | if (root->defrag_running) | ||
346 | continue; | ||
347 | |||
348 | while (1) { | ||
349 | mutex_lock(&root->fs_info->trans_mutex); | ||
350 | record_root_in_trans(root); | ||
351 | mutex_unlock(&root->fs_info->trans_mutex); | ||
352 | |||
353 | root->defrag_running = 1; | ||
354 | err = btrfs_defrag_leaves(trans, root, 1); | ||
355 | btrfs_end_transaction(trans, tree_root); | ||
356 | mutex_unlock(&info->fs_mutex); | ||
357 | |||
358 | btrfs_btree_balance_dirty(root); | ||
359 | cond_resched(); | ||
360 | |||
361 | mutex_lock(&info->fs_mutex); | ||
362 | trans = btrfs_start_transaction(tree_root, 1); | ||
363 | if (err != -EAGAIN) | ||
364 | break; | ||
365 | } | ||
366 | root->defrag_running = 0; | ||
367 | radix_tree_tag_clear(&info->fs_roots_radix, | ||
368 | (unsigned long)root->root_key.objectid, | ||
369 | BTRFS_ROOT_DEFRAG_TAG); | ||
370 | } | 372 | } |
371 | } | 373 | } |
372 | btrfs_end_transaction(trans, tree_root); | 374 | btrfs_defrag_root(info->extent_root, 1); |
373 | return err; | 375 | return err; |
374 | } | 376 | } |
375 | 377 | ||
@@ -527,6 +529,20 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
527 | return ret; | 529 | return ret; |
528 | } | 530 | } |
529 | 531 | ||
532 | int btrfs_clean_old_snapshots(struct btrfs_root *root) | ||
533 | { | ||
534 | struct list_head dirty_roots; | ||
535 | INIT_LIST_HEAD(&dirty_roots); | ||
536 | |||
537 | mutex_lock(&root->fs_info->trans_mutex); | ||
538 | list_splice_init(&root->fs_info->dead_roots, &dirty_roots); | ||
539 | mutex_unlock(&root->fs_info->trans_mutex); | ||
540 | |||
541 | if (!list_empty(&dirty_roots)) { | ||
542 | drop_dirty_roots(root, &dirty_roots); | ||
543 | } | ||
544 | return 0; | ||
545 | } | ||
530 | void btrfs_transaction_cleaner(struct work_struct *work) | 546 | void btrfs_transaction_cleaner(struct work_struct *work) |
531 | { | 547 | { |
532 | struct btrfs_fs_info *fs_info = container_of(work, | 548 | struct btrfs_fs_info *fs_info = container_of(work, |
@@ -536,12 +552,10 @@ void btrfs_transaction_cleaner(struct work_struct *work) | |||
536 | struct btrfs_root *root = fs_info->tree_root; | 552 | struct btrfs_root *root = fs_info->tree_root; |
537 | struct btrfs_transaction *cur; | 553 | struct btrfs_transaction *cur; |
538 | struct btrfs_trans_handle *trans; | 554 | struct btrfs_trans_handle *trans; |
539 | struct list_head dirty_roots; | ||
540 | unsigned long now; | 555 | unsigned long now; |
541 | unsigned long delay = HZ * 30; | 556 | unsigned long delay = HZ * 30; |
542 | int ret; | 557 | int ret; |
543 | 558 | ||
544 | INIT_LIST_HEAD(&dirty_roots); | ||
545 | mutex_lock(&root->fs_info->fs_mutex); | 559 | mutex_lock(&root->fs_info->fs_mutex); |
546 | mutex_lock(&root->fs_info->trans_mutex); | 560 | mutex_lock(&root->fs_info->trans_mutex); |
547 | cur = root->fs_info->running_transaction; | 561 | cur = root->fs_info->running_transaction; |
@@ -561,14 +575,7 @@ void btrfs_transaction_cleaner(struct work_struct *work) | |||
561 | ret = btrfs_commit_transaction(trans, root); | 575 | ret = btrfs_commit_transaction(trans, root); |
562 | out: | 576 | out: |
563 | mutex_unlock(&root->fs_info->fs_mutex); | 577 | mutex_unlock(&root->fs_info->fs_mutex); |
564 | 578 | btrfs_clean_old_snapshots(root); | |
565 | mutex_lock(&root->fs_info->trans_mutex); | ||
566 | list_splice_init(&root->fs_info->dead_roots, &dirty_roots); | ||
567 | mutex_unlock(&root->fs_info->trans_mutex); | ||
568 | |||
569 | if (!list_empty(&dirty_roots)) { | ||
570 | drop_dirty_roots(root, &dirty_roots); | ||
571 | } | ||
572 | btrfs_transaction_queue_work(root, delay); | 579 | btrfs_transaction_queue_work(root, delay); |
573 | } | 580 | } |
574 | 581 | ||
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 65a395eeca91..d5f491d3757e 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -73,5 +73,7 @@ void btrfs_init_transaction_sys(void); | |||
73 | void btrfs_exit_transaction_sys(void); | 73 | void btrfs_exit_transaction_sys(void); |
74 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list); | 74 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list); |
75 | int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info); | 75 | int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info); |
76 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly); | ||
77 | int btrfs_clean_old_snapshots(struct btrfs_root *root); | ||
76 | 78 | ||
77 | #endif | 79 | #endif |
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index 7ea66b4aa5c2..a09064a9a41c 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c | |||
@@ -42,16 +42,20 @@ static void reada_defrag(struct btrfs_root *root, | |||
42 | static int defrag_walk_down(struct btrfs_trans_handle *trans, | 42 | static int defrag_walk_down(struct btrfs_trans_handle *trans, |
43 | struct btrfs_root *root, | 43 | struct btrfs_root *root, |
44 | struct btrfs_path *path, int *level, | 44 | struct btrfs_path *path, int *level, |
45 | int cache_only) | 45 | int cache_only, u64 *last_ret) |
46 | { | 46 | { |
47 | struct buffer_head *next; | 47 | struct buffer_head *next; |
48 | struct buffer_head *cur; | 48 | struct buffer_head *cur; |
49 | u64 blocknr; | 49 | u64 blocknr; |
50 | int ret = 0; | 50 | int ret = 0; |
51 | int is_extent = 0; | ||
51 | 52 | ||
52 | WARN_ON(*level < 0); | 53 | WARN_ON(*level < 0); |
53 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 54 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
54 | 55 | ||
56 | if (root->fs_info->extent_root == root) | ||
57 | is_extent = 1; | ||
58 | |||
55 | while(*level > 0) { | 59 | while(*level > 0) { |
56 | WARN_ON(*level < 0); | 60 | WARN_ON(*level < 0); |
57 | WARN_ON(*level >= BTRFS_MAX_LEVEL); | 61 | WARN_ON(*level >= BTRFS_MAX_LEVEL); |
@@ -70,7 +74,10 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
70 | if (*level == 1) { | 74 | if (*level == 1) { |
71 | ret = btrfs_realloc_node(trans, root, | 75 | ret = btrfs_realloc_node(trans, root, |
72 | path->nodes[*level], | 76 | path->nodes[*level], |
73 | cache_only); | 77 | cache_only, last_ret); |
78 | if (is_extent) | ||
79 | btrfs_extent_post_op(trans, root); | ||
80 | |||
74 | break; | 81 | break; |
75 | } | 82 | } |
76 | blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur), | 83 | blocknr = btrfs_node_blockptr(btrfs_buffer_node(cur), |
@@ -90,8 +97,13 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, | |||
90 | ret = btrfs_cow_block(trans, root, next, path->nodes[*level], | 97 | ret = btrfs_cow_block(trans, root, next, path->nodes[*level], |
91 | path->slots[*level], &next); | 98 | path->slots[*level], &next); |
92 | BUG_ON(ret); | 99 | BUG_ON(ret); |
93 | ret = btrfs_realloc_node(trans, root, next, cache_only); | 100 | ret = btrfs_realloc_node(trans, root, next, cache_only, |
101 | last_ret); | ||
94 | BUG_ON(ret); | 102 | BUG_ON(ret); |
103 | |||
104 | if (is_extent) | ||
105 | btrfs_extent_post_op(trans, root); | ||
106 | |||
95 | WARN_ON(*level <= 0); | 107 | WARN_ON(*level <= 0); |
96 | if (path->nodes[*level-1]) | 108 | if (path->nodes[*level-1]) |
97 | btrfs_block_release(root, path->nodes[*level-1]); | 109 | btrfs_block_release(root, path->nodes[*level-1]); |
@@ -148,10 +160,14 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
148 | int level; | 160 | int level; |
149 | int orig_level; | 161 | int orig_level; |
150 | int i; | 162 | int i; |
163 | int is_extent = 0; | ||
164 | u64 last_ret = 0; | ||
165 | |||
166 | if (root->fs_info->extent_root == root) | ||
167 | is_extent = 1; | ||
151 | 168 | ||
152 | if (root->ref_cows == 0) { | 169 | if (root->ref_cows == 0 && !is_extent) |
153 | goto out; | 170 | goto out; |
154 | } | ||
155 | path = btrfs_alloc_path(); | 171 | path = btrfs_alloc_path(); |
156 | if (!path) | 172 | if (!path) |
157 | return -ENOMEM; | 173 | return -ENOMEM; |
@@ -165,16 +181,21 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
165 | get_bh(root->node); | 181 | get_bh(root->node); |
166 | ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); | 182 | ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); |
167 | BUG_ON(ret); | 183 | BUG_ON(ret); |
168 | ret = btrfs_realloc_node(trans, root, root->node, cache_only); | 184 | ret = btrfs_realloc_node(trans, root, root->node, cache_only, |
185 | &last_ret); | ||
169 | BUG_ON(ret); | 186 | BUG_ON(ret); |
170 | path->nodes[level] = root->node; | 187 | path->nodes[level] = root->node; |
171 | path->slots[level] = 0; | 188 | path->slots[level] = 0; |
189 | if (is_extent) | ||
190 | btrfs_extent_post_op(trans, root); | ||
172 | } else { | 191 | } else { |
173 | level = root->defrag_level; | 192 | level = root->defrag_level; |
174 | path->lowest_level = level; | 193 | path->lowest_level = level; |
175 | wret = btrfs_search_slot(trans, root, &root->defrag_progress, | 194 | wret = btrfs_search_slot(trans, root, &root->defrag_progress, |
176 | path, 0, 1); | 195 | path, 0, 1); |
177 | 196 | ||
197 | if (is_extent) | ||
198 | btrfs_extent_post_op(trans, root); | ||
178 | if (wret < 0) { | 199 | if (wret < 0) { |
179 | ret = wret; | 200 | ret = wret; |
180 | goto out; | 201 | goto out; |
@@ -188,7 +209,8 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
188 | } | 209 | } |
189 | 210 | ||
190 | while(1) { | 211 | while(1) { |
191 | wret = defrag_walk_down(trans, root, path, &level, cache_only); | 212 | wret = defrag_walk_down(trans, root, path, &level, cache_only, |
213 | &last_ret); | ||
192 | if (wret > 0) | 214 | if (wret > 0) |
193 | break; | 215 | break; |
194 | if (wret < 0) | 216 | if (wret < 0) |