btrfs-progs: convert: fix unable to rollback case with removed empty block groups
authorGui Hecheng <guihc.fnst@cn.fujitsu.com>
Wed, 26 Nov 2014 02:43:41 +0000 (10:43 +0800)
committerDavid Sterba <dsterba@suse.cz>
Tue, 9 Dec 2014 13:32:38 +0000 (14:32 +0100)
Run fstests: btrfs/012 will fail with message:
unable to do rollback

It is because the rollback function checks sequentially each piece of space
to map to a certain block group. If some piece doesn't, rollback refuses to continue.

After kernel commit:
commit 47ab2a6c689913db23ccae38349714edf8365e0a
Btrfs: remove empty block groups automatically

Empty block groups are removed, so there are possible gaps:

|--block group 1--| |--block group 2--|
     ^
     |
    gap

So the piece of space of the gap belongs to a removed empty block group,
and rollback should detect this case, and feel free to continue.

Signed-off-by: Gui Hecheng <guihc.fnst@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.cz>
btrfs-convert.c
volumes.c

index 6e2ab0f..4c6c793 100644 (file)
@@ -2418,8 +2418,17 @@ static int may_rollback(struct btrfs_root *root)
        while (1) {
                ret = btrfs_map_block(&info->mapping_tree, WRITE, bytenr,
                                      &length, &multi, 0, NULL);
-               if (ret)
+               if (ret) {
+                       if (ret == -ENOENT) {
+                               /* removed block group at the tail */
+                               if (length == (u64)-1)
+                                       break;
+
+                               /* removed block group in the middle */
+                               goto next;
+                       }
                        goto fail;
+               }
 
                num_stripes = multi->num_stripes;
                physical = multi->stripes[0].physical;
@@ -2427,7 +2436,7 @@ static int may_rollback(struct btrfs_root *root)
 
                if (num_stripes != 1 || physical != bytenr)
                        goto fail;
-
+next:
                bytenr += length;
                if (bytenr >= total_bytes)
                        break;
index a1fd162..a988cdb 100644 (file)
--- a/volumes.c
+++ b/volumes.c
@@ -1318,10 +1318,12 @@ again:
        ce = search_cache_extent(&map_tree->cache_tree, logical);
        if (!ce) {
                kfree(multi);
+               *length = (u64)-1;
                return -ENOENT;
        }
        if (ce->start > logical) {
                kfree(multi);
+               *length = ce->start - logical;
                return -ENOENT;
        }