diff options
Diffstat (limited to 'fs/btrfs/delayed-ref.c')
-rw-r--r-- | fs/btrfs/delayed-ref.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index a405db0320e8..ee181989d444 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c | |||
@@ -155,16 +155,22 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root, | |||
155 | 155 | ||
156 | /* | 156 | /* |
157 | * find an head entry based on bytenr. This returns the delayed ref | 157 | * find an head entry based on bytenr. This returns the delayed ref |
158 | * head if it was able to find one, or NULL if nothing was in that spot | 158 | * head if it was able to find one, or NULL if nothing was in that spot. |
159 | * If return_bigger is given, the next bigger entry is returned if no exact | ||
160 | * match is found. | ||
159 | */ | 161 | */ |
160 | static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root, | 162 | static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root, |
161 | u64 bytenr, | 163 | u64 bytenr, |
162 | struct btrfs_delayed_ref_node **last) | 164 | struct btrfs_delayed_ref_node **last, |
165 | int return_bigger) | ||
163 | { | 166 | { |
164 | struct rb_node *n = root->rb_node; | 167 | struct rb_node *n; |
165 | struct btrfs_delayed_ref_node *entry; | 168 | struct btrfs_delayed_ref_node *entry; |
166 | int cmp; | 169 | int cmp = 0; |
167 | 170 | ||
171 | again: | ||
172 | n = root->rb_node; | ||
173 | entry = NULL; | ||
168 | while (n) { | 174 | while (n) { |
169 | entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); | 175 | entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); |
170 | WARN_ON(!entry->in_tree); | 176 | WARN_ON(!entry->in_tree); |
@@ -187,6 +193,19 @@ static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root, | |||
187 | else | 193 | else |
188 | return entry; | 194 | return entry; |
189 | } | 195 | } |
196 | if (entry && return_bigger) { | ||
197 | if (cmp > 0) { | ||
198 | n = rb_next(&entry->rb_node); | ||
199 | if (!n) | ||
200 | n = rb_first(root); | ||
201 | entry = rb_entry(n, struct btrfs_delayed_ref_node, | ||
202 | rb_node); | ||
203 | bytenr = entry->bytenr; | ||
204 | return_bigger = 0; | ||
205 | goto again; | ||
206 | } | ||
207 | return entry; | ||
208 | } | ||
190 | return NULL; | 209 | return NULL; |
191 | } | 210 | } |
192 | 211 | ||
@@ -246,20 +265,8 @@ int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, | |||
246 | node = rb_first(&delayed_refs->root); | 265 | node = rb_first(&delayed_refs->root); |
247 | } else { | 266 | } else { |
248 | ref = NULL; | 267 | ref = NULL; |
249 | find_ref_head(&delayed_refs->root, start, &ref); | 268 | find_ref_head(&delayed_refs->root, start + 1, &ref, 1); |
250 | if (ref) { | 269 | if (ref) { |
251 | struct btrfs_delayed_ref_node *tmp; | ||
252 | |||
253 | node = rb_prev(&ref->rb_node); | ||
254 | while (node) { | ||
255 | tmp = rb_entry(node, | ||
256 | struct btrfs_delayed_ref_node, | ||
257 | rb_node); | ||
258 | if (tmp->bytenr < start) | ||
259 | break; | ||
260 | ref = tmp; | ||
261 | node = rb_prev(&ref->rb_node); | ||
262 | } | ||
263 | node = &ref->rb_node; | 270 | node = &ref->rb_node; |
264 | } else | 271 | } else |
265 | node = rb_first(&delayed_refs->root); | 272 | node = rb_first(&delayed_refs->root); |
@@ -748,7 +755,7 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr) | |||
748 | struct btrfs_delayed_ref_root *delayed_refs; | 755 | struct btrfs_delayed_ref_root *delayed_refs; |
749 | 756 | ||
750 | delayed_refs = &trans->transaction->delayed_refs; | 757 | delayed_refs = &trans->transaction->delayed_refs; |
751 | ref = find_ref_head(&delayed_refs->root, bytenr, NULL); | 758 | ref = find_ref_head(&delayed_refs->root, bytenr, NULL, 0); |
752 | if (ref) | 759 | if (ref) |
753 | return btrfs_delayed_node_to_head(ref); | 760 | return btrfs_delayed_node_to_head(ref); |
754 | return NULL; | 761 | return NULL; |