]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Btrfs: Fix allocation completions in tree log replay
authorChris Mason <chris.mason@oracle.com>
Wed, 24 Sep 2008 15:23:25 +0000 (11:23 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 19:41:59 +0000 (15:41 -0400)
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>
fs/btrfs/free-space-cache.c

index 01c26e8ae555e5c29f0844760340025a6c23dbe7..f1d9b6bc23ba71e1f68dd3032cba857350007461 100644 (file)
@@ -306,11 +306,45 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
 
                ret = link_free_space(block_group, info);
                BUG_ON(ret);
+       } else if (info && info->offset < offset &&
+                  info->offset + info->bytes >= offset + bytes) {
+               u64 old_start = info->offset;
+               /*
+                * we're freeing space in the middle of the info,
+                * this can happen during tree log replay
+                *
+                * first unlink the old info and then
+                * insert it again after the hole we're creating
+                */
+               unlink_free_space(block_group, info);
+               if (offset + bytes < info->offset + info->bytes) {
+                       u64 old_end = info->offset + info->bytes;
+
+                       info->offset = offset + bytes;
+                       info->bytes = old_end - info->offset;
+                       ret = link_free_space(block_group, info);
+                       BUG_ON(ret);
+               } else {
+                       /* the hole we're creating ends at the end
+                        * of the info struct, just free the info
+                        */
+                       kfree(info);
+               }
+
+               /* step two, insert a new info struct to cover anything
+                * before the hole
+                */
+               spin_unlock(&block_group->lock);
+               ret = btrfs_add_free_space(block_group, old_start,
+                                          offset - old_start);
+               BUG_ON(ret);
+               goto out_nolock;
        } else {
                WARN_ON(1);
        }
 out:
        spin_unlock(&block_group->lock);
+out_nolock:
        return ret;
 }