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:04 -0400 |
commit | 3f157a2fd2ad731e1ed9964fecdc5f459f04a4a4 (patch) | |
tree | df9421e7b1d0c06d5efb8659f4317438d3d511d7 | |
parent | 1b1e2135dc1e4efbcf25ac9ac9979316d4e1193e (diff) |
Btrfs: Online btree defragmentation fixes
The btree defragger wasn't making forward progress because the new key wasn't
being saved by the btrfs_search_forward function.
This also disables the automatic btree defrag, it wasn't scaling well to
huge filesystems. The auto-defrag needs to be done differently.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.c | 170 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 7 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 61 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 6 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 2 | ||||
-rw-r--r-- | fs/btrfs/super.c | 1 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 35 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 | ||||
-rw-r--r-- | fs/btrfs/tree-defrag.c | 36 |
9 files changed, 190 insertions, 129 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 7f4cc2b88d09..0cb80f32a9c7 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -63,10 +63,9 @@ void btrfs_free_path(struct btrfs_path *p) | |||
63 | void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) | 63 | void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) |
64 | { | 64 | { |
65 | int i; | 65 | int i; |
66 | int keep = p->keep_locks; | ||
67 | int skip = p->skip_locking; | ||
68 | 66 | ||
69 | for (i = 0; i < BTRFS_MAX_LEVEL; i++) { | 67 | for (i = 0; i < BTRFS_MAX_LEVEL; i++) { |
68 | p->slots[i] = 0; | ||
70 | if (!p->nodes[i]) | 69 | if (!p->nodes[i]) |
71 | continue; | 70 | continue; |
72 | if (p->locks[i]) { | 71 | if (p->locks[i]) { |
@@ -74,10 +73,8 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) | |||
74 | p->locks[i] = 0; | 73 | p->locks[i] = 0; |
75 | } | 74 | } |
76 | free_extent_buffer(p->nodes[i]); | 75 | free_extent_buffer(p->nodes[i]); |
76 | p->nodes[i] = NULL; | ||
77 | } | 77 | } |
78 | memset(p, 0, sizeof(*p)); | ||
79 | p->keep_locks = keep; | ||
80 | p->skip_locking = skip; | ||
81 | } | 78 | } |
82 | 79 | ||
83 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root) | 80 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root) |
@@ -463,8 +460,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
463 | search_start = cur->start; | 460 | search_start = cur->start; |
464 | last_block = cur->start; | 461 | last_block = cur->start; |
465 | *last_ret = search_start; | 462 | *last_ret = search_start; |
466 | if (parent_level == 1) | ||
467 | btrfs_clear_buffer_defrag(cur); | ||
468 | btrfs_tree_unlock(cur); | 463 | btrfs_tree_unlock(cur); |
469 | free_extent_buffer(cur); | 464 | free_extent_buffer(cur); |
470 | } | 465 | } |
@@ -2969,8 +2964,138 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) | |||
2969 | return 1; | 2964 | return 1; |
2970 | } | 2965 | } |
2971 | 2966 | ||
2967 | /* | ||
2968 | * A helper function to walk down the tree starting at min_key, and looking | ||
2969 | * for nodes or leaves that are either in cache or have a minimum | ||
2970 | * transaction id. This is used by the btree defrag code, but could | ||
2971 | * also be used to search for blocks that have changed since a given | ||
2972 | * transaction id. | ||
2973 | * | ||
2974 | * This does not cow, but it does stuff the starting key it finds back | ||
2975 | * into min_key, so you can call btrfs_search_slot with cow=1 on the | ||
2976 | * key and get a writable path. | ||
2977 | * | ||
2978 | * This does lock as it descends, and path->keep_locks should be set | ||
2979 | * to 1 by the caller. | ||
2980 | * | ||
2981 | * This honors path->lowest_level to prevent descent past a given level | ||
2982 | * of the tree. | ||
2983 | * | ||
2984 | * returns zero if something useful was found, < 0 on error and 1 if there | ||
2985 | * was nothing in the tree that matched the search criteria. | ||
2986 | */ | ||
2987 | int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, | ||
2988 | struct btrfs_path *path, int cache_only, | ||
2989 | u64 min_trans) | ||
2990 | { | ||
2991 | struct extent_buffer *cur; | ||
2992 | struct btrfs_key found_key; | ||
2993 | int slot; | ||
2994 | u32 nritems; | ||
2995 | int level; | ||
2996 | int ret = 1; | ||
2997 | |||
2998 | again: | ||
2999 | cur = btrfs_lock_root_node(root); | ||
3000 | level = btrfs_header_level(cur); | ||
3001 | path->nodes[level] = cur; | ||
3002 | path->locks[level] = 1; | ||
3003 | |||
3004 | if (btrfs_header_generation(cur) < min_trans) { | ||
3005 | ret = 1; | ||
3006 | goto out; | ||
3007 | } | ||
3008 | while(1) { | ||
3009 | nritems = btrfs_header_nritems(cur); | ||
3010 | level = btrfs_header_level(cur); | ||
3011 | bin_search(cur, min_key, level, &slot); | ||
3012 | |||
3013 | /* at level = 0, we're done, setup the path and exit */ | ||
3014 | if (level == 0) { | ||
3015 | ret = 0; | ||
3016 | path->slots[level] = slot; | ||
3017 | btrfs_item_key_to_cpu(cur, &found_key, slot); | ||
3018 | goto out; | ||
3019 | } | ||
3020 | /* | ||
3021 | * check this node pointer against the cache_only and | ||
3022 | * min_trans parameters. If it isn't in cache or is too | ||
3023 | * old, skip to the next one. | ||
3024 | */ | ||
3025 | while(slot < nritems) { | ||
3026 | u64 blockptr; | ||
3027 | u64 gen; | ||
3028 | struct extent_buffer *tmp; | ||
3029 | blockptr = btrfs_node_blockptr(cur, slot); | ||
3030 | gen = btrfs_node_ptr_generation(cur, slot); | ||
3031 | if (gen < min_trans) { | ||
3032 | slot++; | ||
3033 | continue; | ||
3034 | } | ||
3035 | if (!cache_only) | ||
3036 | break; | ||
3037 | |||
3038 | tmp = btrfs_find_tree_block(root, blockptr, | ||
3039 | btrfs_level_size(root, level - 1)); | ||
3040 | |||
3041 | if (tmp && btrfs_buffer_uptodate(tmp, gen)) { | ||
3042 | free_extent_buffer(tmp); | ||
3043 | break; | ||
3044 | } | ||
3045 | if (tmp) | ||
3046 | free_extent_buffer(tmp); | ||
3047 | slot++; | ||
3048 | } | ||
3049 | /* | ||
3050 | * we didn't find a candidate key in this node, walk forward | ||
3051 | * and find another one | ||
3052 | */ | ||
3053 | if (slot >= nritems) { | ||
3054 | ret = btrfs_find_next_key(root, path, min_key, level, | ||
3055 | cache_only, min_trans); | ||
3056 | if (ret == 0) { | ||
3057 | btrfs_release_path(root, path); | ||
3058 | goto again; | ||
3059 | } else { | ||
3060 | goto out; | ||
3061 | } | ||
3062 | } | ||
3063 | /* save our key for returning back */ | ||
3064 | btrfs_node_key_to_cpu(cur, &found_key, slot); | ||
3065 | path->slots[level] = slot; | ||
3066 | if (level == path->lowest_level) { | ||
3067 | ret = 0; | ||
3068 | unlock_up(path, level, 1); | ||
3069 | goto out; | ||
3070 | } | ||
3071 | cur = read_node_slot(root, cur, slot); | ||
3072 | |||
3073 | btrfs_tree_lock(cur); | ||
3074 | path->locks[level - 1] = 1; | ||
3075 | path->nodes[level - 1] = cur; | ||
3076 | unlock_up(path, level, 1); | ||
3077 | } | ||
3078 | out: | ||
3079 | if (ret == 0) | ||
3080 | memcpy(min_key, &found_key, sizeof(found_key)); | ||
3081 | return ret; | ||
3082 | } | ||
3083 | |||
3084 | /* | ||
3085 | * this is similar to btrfs_next_leaf, but does not try to preserve | ||
3086 | * and fixup the path. It looks for and returns the next key in the | ||
3087 | * tree based on the current path and the cache_only and min_trans | ||
3088 | * parameters. | ||
3089 | * | ||
3090 | * 0 is returned if another key is found, < 0 if there are any errors | ||
3091 | * and 1 is returned if there are no higher keys in the tree | ||
3092 | * | ||
3093 | * path->keep_locks should be set to 1 on the search made before | ||
3094 | * calling this function. | ||
3095 | */ | ||
2972 | int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, | 3096 | int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, |
2973 | struct btrfs_key *key, int lowest_level) | 3097 | struct btrfs_key *key, int lowest_level, |
3098 | int cache_only, u64 min_trans) | ||
2974 | { | 3099 | { |
2975 | int level = lowest_level; | 3100 | int level = lowest_level; |
2976 | int slot; | 3101 | int slot; |
@@ -2982,6 +3107,7 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, | |||
2982 | 3107 | ||
2983 | slot = path->slots[level] + 1; | 3108 | slot = path->slots[level] + 1; |
2984 | c = path->nodes[level]; | 3109 | c = path->nodes[level]; |
3110 | next: | ||
2985 | if (slot >= btrfs_header_nritems(c)) { | 3111 | if (slot >= btrfs_header_nritems(c)) { |
2986 | level++; | 3112 | level++; |
2987 | if (level == BTRFS_MAX_LEVEL) { | 3113 | if (level == BTRFS_MAX_LEVEL) { |
@@ -2991,8 +3117,28 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, | |||
2991 | } | 3117 | } |
2992 | if (level == 0) | 3118 | if (level == 0) |
2993 | btrfs_item_key_to_cpu(c, key, slot); | 3119 | btrfs_item_key_to_cpu(c, key, slot); |
2994 | else | 3120 | else { |
3121 | u64 blockptr = btrfs_node_blockptr(c, slot); | ||
3122 | u64 gen = btrfs_node_ptr_generation(c, slot); | ||
3123 | |||
3124 | if (cache_only) { | ||
3125 | struct extent_buffer *cur; | ||
3126 | cur = btrfs_find_tree_block(root, blockptr, | ||
3127 | btrfs_level_size(root, level - 1)); | ||
3128 | if (!cur || !btrfs_buffer_uptodate(cur, gen)) { | ||
3129 | slot++; | ||
3130 | if (cur) | ||
3131 | free_extent_buffer(cur); | ||
3132 | goto next; | ||
3133 | } | ||
3134 | free_extent_buffer(cur); | ||
3135 | } | ||
3136 | if (gen < min_trans) { | ||
3137 | slot++; | ||
3138 | goto next; | ||
3139 | } | ||
2995 | btrfs_node_key_to_cpu(c, key, slot); | 3140 | btrfs_node_key_to_cpu(c, key, slot); |
3141 | } | ||
2996 | return 0; | 3142 | return 0; |
2997 | } | 3143 | } |
2998 | return 1; | 3144 | return 1; |
@@ -3095,6 +3241,12 @@ done: | |||
3095 | return 0; | 3241 | return 0; |
3096 | } | 3242 | } |
3097 | 3243 | ||
3244 | /* | ||
3245 | * this uses btrfs_prev_leaf to walk backwards in the tree, and keeps | ||
3246 | * searching until it gets past min_objectid or finds an item of 'type' | ||
3247 | * | ||
3248 | * returns 0 if something is found, 1 if nothing was found and < 0 on error | ||
3249 | */ | ||
3098 | int btrfs_previous_item(struct btrfs_root *root, | 3250 | int btrfs_previous_item(struct btrfs_root *root, |
3099 | struct btrfs_path *path, u64 min_objectid, | 3251 | struct btrfs_path *path, u64 min_objectid, |
3100 | int type) | 3252 | int type) |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ca8e6f15859e..a28796482b4a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -609,6 +609,7 @@ struct btrfs_root { | |||
609 | u64 last_inode_alloc; | 609 | u64 last_inode_alloc; |
610 | int ref_cows; | 610 | int ref_cows; |
611 | int track_dirty; | 611 | int track_dirty; |
612 | u64 defrag_trans_start; | ||
612 | struct btrfs_key defrag_progress; | 613 | struct btrfs_key defrag_progress; |
613 | struct btrfs_key defrag_max; | 614 | struct btrfs_key defrag_max; |
614 | int defrag_running; | 615 | int defrag_running; |
@@ -1412,7 +1413,11 @@ int btrfs_previous_item(struct btrfs_root *root, | |||
1412 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root); | 1413 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root); |
1413 | struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root); | 1414 | struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root); |
1414 | int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, | 1415 | int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, |
1415 | struct btrfs_key *key, int lowest_level); | 1416 | struct btrfs_key *key, int lowest_level, |
1417 | int cache_only, u64 min_trans); | ||
1418 | int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, | ||
1419 | struct btrfs_path *path, int cache_only, | ||
1420 | u64 min_trans); | ||
1416 | 1421 | ||
1417 | int btrfs_cow_block(struct btrfs_trans_handle *trans, | 1422 | int btrfs_cow_block(struct btrfs_trans_handle *trans, |
1418 | struct btrfs_root *root, struct extent_buffer *buf, | 1423 | struct btrfs_root *root, struct extent_buffer *buf, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 31ca9f89388d..4cdc0b6a2672 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -295,7 +295,6 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
295 | ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE, | 295 | ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE, |
296 | btrfs_header_generation(eb)); | 296 | btrfs_header_generation(eb)); |
297 | BUG_ON(ret); | 297 | BUG_ON(ret); |
298 | btrfs_clear_buffer_defrag(eb); | ||
299 | found_start = btrfs_header_bytenr(eb); | 298 | found_start = btrfs_header_bytenr(eb); |
300 | if (found_start != start) { | 299 | if (found_start != start) { |
301 | printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", | 300 | printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", |
@@ -355,7 +354,6 @@ int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
355 | } | 354 | } |
356 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); | 355 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); |
357 | 356 | ||
358 | btrfs_clear_buffer_defrag(eb); | ||
359 | found_start = btrfs_header_bytenr(eb); | 357 | found_start = btrfs_header_bytenr(eb); |
360 | if (found_start != start) { | 358 | if (found_start != start) { |
361 | ret = -EIO; | 359 | ret = -EIO; |
@@ -736,6 +734,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
736 | memset(&root->root_item, 0, sizeof(root->root_item)); | 734 | memset(&root->root_item, 0, sizeof(root->root_item)); |
737 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); | 735 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); |
738 | memset(&root->root_kobj, 0, sizeof(root->root_kobj)); | 736 | memset(&root->root_kobj, 0, sizeof(root->root_kobj)); |
737 | root->defrag_trans_start = fs_info->generation; | ||
739 | init_completion(&root->kobj_unregister); | 738 | init_completion(&root->kobj_unregister); |
740 | root->defrag_running = 0; | 739 | root->defrag_running = 0; |
741 | root->defrag_level = 0; | 740 | root->defrag_level = 0; |
@@ -1168,7 +1167,6 @@ static int transaction_kthread(void *arg) | |||
1168 | goto sleep; | 1167 | goto sleep; |
1169 | } | 1168 | } |
1170 | mutex_unlock(&root->fs_info->trans_mutex); | 1169 | mutex_unlock(&root->fs_info->trans_mutex); |
1171 | btrfs_defrag_dirty_roots(root->fs_info); | ||
1172 | trans = btrfs_start_transaction(root, 1); | 1170 | trans = btrfs_start_transaction(root, 1); |
1173 | ret = btrfs_commit_transaction(trans, root); | 1171 | ret = btrfs_commit_transaction(trans, root); |
1174 | sleep: | 1172 | sleep: |
@@ -1434,12 +1432,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1434 | tree_root, | 1432 | tree_root, |
1435 | "btrfs-transaction"); | 1433 | "btrfs-transaction"); |
1436 | if (!fs_info->transaction_kthread) | 1434 | if (!fs_info->transaction_kthread) |
1437 | goto fail_trans_kthread; | 1435 | goto fail_cleaner; |
1438 | 1436 | ||
1439 | 1437 | ||
1440 | return tree_root; | 1438 | return tree_root; |
1441 | 1439 | ||
1442 | fail_trans_kthread: | 1440 | fail_cleaner: |
1443 | kthread_stop(fs_info->cleaner_kthread); | 1441 | kthread_stop(fs_info->cleaner_kthread); |
1444 | fail_extent_root: | 1442 | fail_extent_root: |
1445 | free_extent_buffer(extent_root->node); | 1443 | free_extent_buffer(extent_root->node); |
@@ -1662,7 +1660,6 @@ int close_ctree(struct btrfs_root *root) | |||
1662 | kthread_stop(root->fs_info->transaction_kthread); | 1660 | kthread_stop(root->fs_info->transaction_kthread); |
1663 | kthread_stop(root->fs_info->cleaner_kthread); | 1661 | kthread_stop(root->fs_info->cleaner_kthread); |
1664 | 1662 | ||
1665 | btrfs_defrag_dirty_roots(root->fs_info); | ||
1666 | btrfs_clean_old_snapshots(root); | 1663 | btrfs_clean_old_snapshots(root); |
1667 | trans = btrfs_start_transaction(root, 1); | 1664 | trans = btrfs_start_transaction(root, 1); |
1668 | ret = btrfs_commit_transaction(trans, root); | 1665 | ret = btrfs_commit_transaction(trans, root); |
@@ -1794,58 +1791,6 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) | |||
1794 | return; | 1791 | return; |
1795 | } | 1792 | } |
1796 | 1793 | ||
1797 | void btrfs_set_buffer_defrag(struct extent_buffer *buf) | ||
1798 | { | ||
1799 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | ||
1800 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1801 | set_extent_bits(&BTRFS_I(btree_inode)->io_tree, buf->start, | ||
1802 | buf->start + buf->len - 1, EXTENT_DEFRAG, GFP_NOFS); | ||
1803 | } | ||
1804 | |||
1805 | void btrfs_set_buffer_defrag_done(struct extent_buffer *buf) | ||
1806 | { | ||
1807 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | ||
1808 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1809 | set_extent_bits(&BTRFS_I(btree_inode)->io_tree, buf->start, | ||
1810 | buf->start + buf->len - 1, EXTENT_DEFRAG_DONE, | ||
1811 | GFP_NOFS); | ||
1812 | } | ||
1813 | |||
1814 | int btrfs_buffer_defrag(struct extent_buffer *buf) | ||
1815 | { | ||
1816 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | ||
1817 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1818 | return test_range_bit(&BTRFS_I(btree_inode)->io_tree, | ||
1819 | buf->start, buf->start + buf->len - 1, EXTENT_DEFRAG, 0); | ||
1820 | } | ||
1821 | |||
1822 | int btrfs_buffer_defrag_done(struct extent_buffer *buf) | ||
1823 | { | ||
1824 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | ||
1825 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1826 | return test_range_bit(&BTRFS_I(btree_inode)->io_tree, | ||
1827 | buf->start, buf->start + buf->len - 1, | ||
1828 | EXTENT_DEFRAG_DONE, 0); | ||
1829 | } | ||
1830 | |||
1831 | int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf) | ||
1832 | { | ||
1833 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | ||
1834 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1835 | return clear_extent_bits(&BTRFS_I(btree_inode)->io_tree, | ||
1836 | buf->start, buf->start + buf->len - 1, | ||
1837 | EXTENT_DEFRAG_DONE, GFP_NOFS); | ||
1838 | } | ||
1839 | |||
1840 | int btrfs_clear_buffer_defrag(struct extent_buffer *buf) | ||
1841 | { | ||
1842 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | ||
1843 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1844 | return clear_extent_bits(&BTRFS_I(btree_inode)->io_tree, | ||
1845 | buf->start, buf->start + buf->len - 1, | ||
1846 | EXTENT_DEFRAG, GFP_NOFS); | ||
1847 | } | ||
1848 | |||
1849 | int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) | 1794 | int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) |
1850 | { | 1795 | { |
1851 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | 1796 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index deff6b4815a7..353c3c50c957 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -61,12 +61,6 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid); | |||
61 | int btrfs_set_buffer_uptodate(struct extent_buffer *buf); | 61 | int btrfs_set_buffer_uptodate(struct extent_buffer *buf); |
62 | int wait_on_tree_block_writeback(struct btrfs_root *root, | 62 | int wait_on_tree_block_writeback(struct btrfs_root *root, |
63 | struct extent_buffer *buf); | 63 | struct extent_buffer *buf); |
64 | void btrfs_set_buffer_defrag(struct extent_buffer *buf); | ||
65 | void btrfs_set_buffer_defrag_done(struct extent_buffer *buf); | ||
66 | int btrfs_buffer_defrag(struct extent_buffer *buf); | ||
67 | int btrfs_buffer_defrag_done(struct extent_buffer *buf); | ||
68 | int btrfs_clear_buffer_defrag(struct extent_buffer *buf); | ||
69 | int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf); | ||
70 | int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); | 64 | int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); |
71 | u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); | 65 | u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); |
72 | void btrfs_csum_final(u32 crc, char *result); | 66 | void btrfs_csum_final(u32 crc, char *result); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index dc3c03c6612d..5e0857ffbc35 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2095,8 +2095,6 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
2095 | 2095 | ||
2096 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, | 2096 | set_extent_dirty(&trans->transaction->dirty_pages, buf->start, |
2097 | buf->start + buf->len - 1, GFP_NOFS); | 2097 | buf->start + buf->len - 1, GFP_NOFS); |
2098 | if (!btrfs_test_opt(root, SSD)) | ||
2099 | btrfs_set_buffer_defrag(buf); | ||
2100 | trans->blocks_used++; | 2098 | trans->blocks_used++; |
2101 | return buf; | 2099 | return buf; |
2102 | } | 2100 | } |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 726d6871fa13..5e28cf5c2e85 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -365,7 +365,6 @@ int btrfs_sync_fs(struct super_block *sb, int wait) | |||
365 | return 0; | 365 | return 0; |
366 | } | 366 | } |
367 | btrfs_clean_old_snapshots(root); | 367 | btrfs_clean_old_snapshots(root); |
368 | btrfs_defrag_dirty_roots(root->fs_info); | ||
369 | trans = btrfs_start_transaction(root, 1); | 368 | trans = btrfs_start_transaction(root, 1); |
370 | ret = btrfs_commit_transaction(trans, root); | 369 | ret = btrfs_commit_transaction(trans, root); |
371 | sb->s_dirt = 0; | 370 | sb->s_dirt = 0; |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 8e909cb97c6d..98f422d9ab07 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -30,7 +30,6 @@ extern struct kmem_cache *btrfs_trans_handle_cachep; | |||
30 | extern struct kmem_cache *btrfs_transaction_cachep; | 30 | extern struct kmem_cache *btrfs_transaction_cachep; |
31 | 31 | ||
32 | #define BTRFS_ROOT_TRANS_TAG 0 | 32 | #define BTRFS_ROOT_TRANS_TAG 0 |
33 | #define BTRFS_ROOT_DEFRAG_TAG 1 | ||
34 | 33 | ||
35 | static noinline void put_transaction(struct btrfs_transaction *transaction) | 34 | static noinline void put_transaction(struct btrfs_transaction *transaction) |
36 | { | 35 | { |
@@ -92,9 +91,6 @@ static noinline int record_root_in_trans(struct btrfs_root *root) | |||
92 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, | 91 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, |
93 | (unsigned long)root->root_key.objectid, | 92 | (unsigned long)root->root_key.objectid, |
94 | BTRFS_ROOT_TRANS_TAG); | 93 | BTRFS_ROOT_TRANS_TAG); |
95 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, | ||
96 | (unsigned long)root->root_key.objectid, | ||
97 | BTRFS_ROOT_DEFRAG_TAG); | ||
98 | root->commit_root = btrfs_root_node(root); | 94 | root->commit_root = btrfs_root_node(root); |
99 | } else { | 95 | } else { |
100 | WARN_ON(1); | 96 | WARN_ON(1); |
@@ -403,44 +399,15 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | |||
403 | cond_resched(); | 399 | cond_resched(); |
404 | 400 | ||
405 | trans = btrfs_start_transaction(root, 1); | 401 | trans = btrfs_start_transaction(root, 1); |
406 | if (ret != -EAGAIN) | 402 | if (root->fs_info->closing || ret != -EAGAIN) |
407 | break; | 403 | break; |
408 | } | 404 | } |
409 | root->defrag_running = 0; | 405 | root->defrag_running = 0; |
410 | smp_mb(); | 406 | smp_mb(); |
411 | radix_tree_tag_clear(&info->fs_roots_radix, | ||
412 | (unsigned long)root->root_key.objectid, | ||
413 | BTRFS_ROOT_DEFRAG_TAG); | ||
414 | btrfs_end_transaction(trans, root); | 407 | btrfs_end_transaction(trans, root); |
415 | return 0; | 408 | return 0; |
416 | } | 409 | } |
417 | 410 | ||
418 | int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info) | ||
419 | { | ||
420 | struct btrfs_root *gang[1]; | ||
421 | struct btrfs_root *root; | ||
422 | int i; | ||
423 | int ret; | ||
424 | int err = 0; | ||
425 | u64 last = 0; | ||
426 | |||
427 | while(1) { | ||
428 | ret = radix_tree_gang_lookup_tag(&info->fs_roots_radix, | ||
429 | (void **)gang, last, | ||
430 | ARRAY_SIZE(gang), | ||
431 | BTRFS_ROOT_DEFRAG_TAG); | ||
432 | if (ret == 0) | ||
433 | break; | ||
434 | for (i = 0; i < ret; i++) { | ||
435 | root = gang[i]; | ||
436 | last = root->root_key.objectid + 1; | ||
437 | btrfs_defrag_root(root, 1); | ||
438 | } | ||
439 | } | ||
440 | btrfs_defrag_root(info->extent_root, 1); | ||
441 | return err; | ||
442 | } | ||
443 | |||
444 | static noinline int drop_dirty_roots(struct btrfs_root *tree_root, | 411 | static noinline int drop_dirty_roots(struct btrfs_root *tree_root, |
445 | struct list_head *list) | 412 | struct list_head *list) |
446 | { | 413 | { |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index e1e5a06b65f4..9ccd5a5b170f 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -84,7 +84,6 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | |||
84 | 84 | ||
85 | int btrfs_add_dead_root(struct btrfs_root *root, struct btrfs_root *latest, | 85 | int btrfs_add_dead_root(struct btrfs_root *root, struct btrfs_root *latest, |
86 | struct list_head *dead_list); | 86 | struct list_head *dead_list); |
87 | int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info); | ||
88 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly); | 87 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly); |
89 | int btrfs_clean_old_snapshots(struct btrfs_root *root); | 88 | int btrfs_clean_old_snapshots(struct btrfs_root *root); |
90 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 89 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index b17693f61fbc..cc2650b06952 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c | |||
@@ -32,10 +32,13 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
32 | int wret; | 32 | int wret; |
33 | int level; | 33 | int level; |
34 | int orig_level; | 34 | int orig_level; |
35 | int i; | ||
36 | int is_extent = 0; | 35 | int is_extent = 0; |
37 | int next_key_ret = 0; | 36 | int next_key_ret = 0; |
38 | u64 last_ret = 0; | 37 | u64 last_ret = 0; |
38 | u64 min_trans = 0; | ||
39 | |||
40 | if (cache_only) | ||
41 | goto out; | ||
39 | 42 | ||
40 | if (root->fs_info->extent_root == root) { | 43 | if (root->fs_info->extent_root == root) { |
41 | /* | 44 | /* |
@@ -43,10 +46,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
43 | * we can't defrag the extent root without deadlock | 46 | * we can't defrag the extent root without deadlock |
44 | */ | 47 | */ |
45 | goto out; | 48 | goto out; |
46 | #if 0 | ||
47 | mutex_lock(&root->fs_info->alloc_mutex); | ||
48 | is_extent = 1; | ||
49 | #endif | ||
50 | } | 49 | } |
51 | 50 | ||
52 | if (root->ref_cows == 0 && !is_extent) | 51 | if (root->ref_cows == 0 && !is_extent) |
@@ -84,6 +83,17 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
84 | 83 | ||
85 | path->lowest_level = 1; | 84 | path->lowest_level = 1; |
86 | path->keep_locks = 1; | 85 | path->keep_locks = 1; |
86 | if (cache_only) | ||
87 | min_trans = root->defrag_trans_start; | ||
88 | |||
89 | ret = btrfs_search_forward(root, &key, path, cache_only, min_trans); | ||
90 | if (ret < 0) | ||
91 | goto out; | ||
92 | if (ret > 0) { | ||
93 | ret = 0; | ||
94 | goto out; | ||
95 | } | ||
96 | btrfs_release_path(root, path); | ||
87 | wret = btrfs_search_slot(trans, root, &key, path, 0, 1); | 97 | wret = btrfs_search_slot(trans, root, &key, path, 0, 1); |
88 | 98 | ||
89 | if (wret < 0) { | 99 | if (wret < 0) { |
@@ -95,7 +105,8 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
95 | goto out; | 105 | goto out; |
96 | } | 106 | } |
97 | path->slots[1] = btrfs_header_nritems(path->nodes[1]); | 107 | path->slots[1] = btrfs_header_nritems(path->nodes[1]); |
98 | next_key_ret = btrfs_find_next_key(root, path, &key, 1); | 108 | next_key_ret = btrfs_find_next_key(root, path, &key, 1, cache_only, |
109 | min_trans); | ||
99 | ret = btrfs_realloc_node(trans, root, | 110 | ret = btrfs_realloc_node(trans, root, |
100 | path->nodes[1], 0, | 111 | path->nodes[1], 0, |
101 | cache_only, &last_ret, | 112 | cache_only, &last_ret, |
@@ -106,19 +117,9 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
106 | ret = -EAGAIN; | 117 | ret = -EAGAIN; |
107 | } | 118 | } |
108 | 119 | ||
109 | for (i = 1; i < BTRFS_MAX_LEVEL; i++) { | 120 | btrfs_release_path(root, path); |
110 | if (path->locks[i]) { | ||
111 | btrfs_tree_unlock(path->nodes[i]); | ||
112 | path->locks[i] = 0; | ||
113 | } | ||
114 | if (path->nodes[i]) { | ||
115 | free_extent_buffer(path->nodes[i]); | ||
116 | path->nodes[i] = NULL; | ||
117 | } | ||
118 | } | ||
119 | if (is_extent) | 121 | if (is_extent) |
120 | btrfs_extent_post_op(trans, root); | 122 | btrfs_extent_post_op(trans, root); |
121 | |||
122 | out: | 123 | out: |
123 | if (is_extent) | 124 | if (is_extent) |
124 | mutex_unlock(&root->fs_info->alloc_mutex); | 125 | mutex_unlock(&root->fs_info->alloc_mutex); |
@@ -138,6 +139,7 @@ done: | |||
138 | if (ret != -EAGAIN) { | 139 | if (ret != -EAGAIN) { |
139 | memset(&root->defrag_progress, 0, | 140 | memset(&root->defrag_progress, 0, |
140 | sizeof(root->defrag_progress)); | 141 | sizeof(root->defrag_progress)); |
142 | root->defrag_trans_start = trans->transid; | ||
141 | } | 143 | } |
142 | return ret; | 144 | return ret; |
143 | } | 145 | } |