btrfs-progs: convert: Insert needed holes for superblock migration
authorQu Wenruo <quwenruo@cn.fujitsu.com>
Wed, 1 Jun 2016 08:29:43 +0000 (16:29 +0800)
committerDavid Sterba <dsterba@suse.com>
Tue, 7 Jun 2016 16:15:19 +0000 (18:15 +0200)
New convert doesn't insert holes for superblock migration range.

Unlike the old design, which only relocates 4K (superblock size) to
other places.
In the new design, to make sure convert can handle different page sizes
and align chunks bytenr, we relocate the whole 64K range.

And if there is only a 4K used block inside 64K superblock migration
range, it will make converted the fs have discontiguous file extents.

This patch will fix it by inserting needed holes to avoid such
discontinuous error.

Reported-by: Tsutomu Itoh <t-itoh@jp.fujitsu.com>
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
btrfs-convert.c

index 7cac304ba0b999153d824662202d99da4b9ba947..beec5d7dd4a870701f9dafcb32c028fea1007289 100644 (file)
@@ -1384,6 +1384,8 @@ static int migrate_one_reserved_range(struct btrfs_trans_handle *trans,
 {
        u64 cur_off = start;
        u64 cur_len = len;
+       u64 hole_start = start;
+       u64 hole_len;
        struct cache_extent *cache;
        struct btrfs_key key;
        struct extent_buffer *eb;
@@ -1435,9 +1437,23 @@ static int migrate_one_reserved_range(struct btrfs_trans_handle *trans,
                        ret = csum_disk_extent(trans, root, key.objectid,
                                               key.offset);
 
+               /* Don't forget to insert hole */
+               hole_len = cur_off - hole_start;
+               if (hole_len) {
+                       ret = btrfs_record_file_extent(trans, root, ino, inode,
+                                       hole_start, 0, hole_len);
+                       if (ret < 0)
+                               break;
+               }
+
                cur_off += key.offset;
+               hole_start = cur_off;
                cur_len = start + len - cur_off;
        }
+       /* Last hole */
+       if (start + len - hole_start > 0)
+               ret = btrfs_record_file_extent(trans, root, ino, inode,
+                               hole_start, 0, start + len - hole_start);
        return ret;
 }