diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-09-24 11:23:25 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 15:41:59 -0400 |
commit | 9b49c9b9f93e148815f2544d0c91f43b6d72eea9 (patch) | |
tree | 2cd29ee73e641a5069128d87a668d4fff3626502 | |
parent | 60582d1e933649f14f46f816bb75049058679e01 (diff) |
Btrfs: Fix allocation completions in tree log replay
After a crash, the tree log code uses btrfs_alloc_logged_extent to
record allocations of data extents that it finds in the log tree. These
come in basically random order, which does not fit how
btrfs_remove_free_space() expects to be called.
btrfs_remove_free_space was changed to support recording an extent
allocation in the middle of a region of free space.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/free-space-cache.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 01c26e8ae555..f1d9b6bc23ba 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
@@ -306,11 +306,45 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, | |||
306 | 306 | ||
307 | ret = link_free_space(block_group, info); | 307 | ret = link_free_space(block_group, info); |
308 | BUG_ON(ret); | 308 | BUG_ON(ret); |
309 | } else if (info && info->offset < offset && | ||
310 | info->offset + info->bytes >= offset + bytes) { | ||
311 | u64 old_start = info->offset; | ||
312 | /* | ||
313 | * we're freeing space in the middle of the info, | ||
314 | * this can happen during tree log replay | ||
315 | * | ||
316 | * first unlink the old info and then | ||
317 | * insert it again after the hole we're creating | ||
318 | */ | ||
319 | unlink_free_space(block_group, info); | ||
320 | if (offset + bytes < info->offset + info->bytes) { | ||
321 | u64 old_end = info->offset + info->bytes; | ||
322 | |||
323 | info->offset = offset + bytes; | ||
324 | info->bytes = old_end - info->offset; | ||
325 | ret = link_free_space(block_group, info); | ||
326 | BUG_ON(ret); | ||
327 | } else { | ||
328 | /* the hole we're creating ends at the end | ||
329 | * of the info struct, just free the info | ||
330 | */ | ||
331 | kfree(info); | ||
332 | } | ||
333 | |||
334 | /* step two, insert a new info struct to cover anything | ||
335 | * before the hole | ||
336 | */ | ||
337 | spin_unlock(&block_group->lock); | ||
338 | ret = btrfs_add_free_space(block_group, old_start, | ||
339 | offset - old_start); | ||
340 | BUG_ON(ret); | ||
341 | goto out_nolock; | ||
309 | } else { | 342 | } else { |
310 | WARN_ON(1); | 343 | WARN_ON(1); |
311 | } | 344 | } |
312 | out: | 345 | out: |
313 | spin_unlock(&block_group->lock); | 346 | spin_unlock(&block_group->lock); |
347 | out_nolock: | ||
314 | return ret; | 348 | return ret; |
315 | } | 349 | } |
316 | 350 | ||