aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-defrag.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-10-15 16:22:39 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:57 -0400
commita6b6e75e096f436f0cc56edf5bca96301e194491 (patch)
tree03751594c29a7d70d317689fd6b5e44ee023633e /fs/btrfs/tree-defrag.c
parentff79f8190b6e955ff7a71faf804a3017d526e657 (diff)
Btrfs: Defrag only leaves, and only when the parent node has a single objectid
This allows us to defrag huge directories, but skip the expensive defrag case in more common usage, where it does not help as much. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/tree-defrag.c')
-rw-r--r--fs/btrfs/tree-defrag.c36
1 files changed, 5 insertions, 31 deletions
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
index f86eccf511b9..b02355a7b143 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -76,7 +76,9 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
76 if (*level == 1) { 76 if (*level == 1) {
77 ret = btrfs_realloc_node(trans, root, 77 ret = btrfs_realloc_node(trans, root,
78 path->nodes[*level], 78 path->nodes[*level],
79 cache_only, last_ret); 79 path->slots[*level],
80 cache_only, last_ret,
81 &root->defrag_progress);
80 if (is_extent) 82 if (is_extent)
81 btrfs_extent_post_op(trans, root); 83 btrfs_extent_post_op(trans, root);
82 84
@@ -100,10 +102,6 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
100 ret = btrfs_cow_block(trans, root, next, path->nodes[*level], 102 ret = btrfs_cow_block(trans, root, next, path->nodes[*level],
101 path->slots[*level], &next); 103 path->slots[*level], &next);
102 BUG_ON(ret); 104 BUG_ON(ret);
103 ret = btrfs_realloc_node(trans, root, next, cache_only,
104 last_ret);
105 BUG_ON(ret);
106
107 if (is_extent) 105 if (is_extent)
108 btrfs_extent_post_op(trans, root); 106 btrfs_extent_post_op(trans, root);
109 107
@@ -122,8 +120,8 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
122 free_extent_buffer(path->nodes[*level]); 120 free_extent_buffer(path->nodes[*level]);
123 path->nodes[*level] = NULL; 121 path->nodes[*level] = NULL;
124 *level += 1; 122 *level += 1;
125 WARN_ON(ret); 123 WARN_ON(ret && ret != -EAGAIN);
126 return 0; 124 return ret;
127} 125}
128 126
129static int defrag_walk_up(struct btrfs_trans_handle *trans, 127static int defrag_walk_up(struct btrfs_trans_handle *trans,
@@ -147,27 +145,6 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans,
147 root->defrag_level = i; 145 root->defrag_level = i;
148 return 0; 146 return 0;
149 } else { 147 } else {
150 if (*level > 1 && path->nodes[*level] != root->node &&
151 btrfs_buffer_defrag(path->nodes[*level])) {
152 struct extent_buffer *next;
153 u64 last;
154 int ret;
155 ret = btrfs_cow_block(trans, root,
156 path->nodes[*level],
157 path->nodes[*level + 1],
158 path->slots[*level + 1],
159 &next);
160 BUG_ON(ret);
161 path->nodes[*level] = next;
162 last = next->start;
163 ret = btrfs_realloc_node(trans, root, next,
164 cache_only, &last);
165 BUG_ON(ret);
166
167 if (root == root->fs_info->extent_root)
168 btrfs_extent_post_op(trans, root);
169 }
170
171 btrfs_clear_buffer_defrag(path->nodes[*level]); 148 btrfs_clear_buffer_defrag(path->nodes[*level]);
172 free_extent_buffer(path->nodes[*level]); 149 free_extent_buffer(path->nodes[*level]);
173 path->nodes[*level] = NULL; 150 path->nodes[*level] = NULL;
@@ -211,9 +188,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
211 extent_buffer_get(root->node); 188 extent_buffer_get(root->node);
212 ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp); 189 ret = btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp);
213 BUG_ON(ret); 190 BUG_ON(ret);
214 ret = btrfs_realloc_node(trans, root, root->node, cache_only,
215 &last_ret);
216 BUG_ON(ret);
217 path->nodes[level] = root->node; 191 path->nodes[level] = root->node;
218 path->slots[level] = 0; 192 path->slots[level] = 0;
219 if (is_extent) 193 if (is_extent)