summaryrefslogtreecommitdiff
path: root/convert.c
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-12-17 16:10:07 -0500
committerChris Mason <chris.mason@oracle.com>2008-12-17 16:10:07 -0500
commit0d53b212d8464c6476e0cda0bbb8533e080816f6 (patch)
tree3438dd3fe0117b0f9d12c0c7642a4120ec085bf6 /convert.c
parentb238b4b072904e3fe72149b68a2e69784893619e (diff)
Btrfs: update converter for the new disk format
This patch updates the ext3 to btrfs converter for the new disk format. This mainly involves changing the convert's data relocation and free space management code. This patch also ports some functions from kernel module to btrfs-progs. Thank you, Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Diffstat (limited to 'convert.c')
-rw-r--r--convert.c391
1 files changed, 277 insertions, 114 deletions
diff --git a/convert.c b/convert.c
index 388c6c44..2cc2a550 100644
--- a/convert.c
+++ b/convert.c
@@ -41,7 +41,11 @@
#include <ext2fs/ext2_fs.h>
#include <ext2fs/ext2fs.h>
#include <ext2fs/ext2_ext_attr.h>
+
#define INO_OFFSET (BTRFS_FIRST_FREE_OBJECTID - EXT2_ROOT_INO)
+#define STRIPE_LEN (64 * 1024)
+#define EXT2_IMAGE_SUBVOL_OBJECTID BTRFS_FIRST_FREE_OBJECTID
+
/*
* Open Ext2fs in readonly mode, read block allocation bitmap and
* inode bitmap into memory.
@@ -101,7 +105,7 @@ static int ext2_free_block(ext2_filsys fs, u64 block)
static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs)
{
- int ret = 0;
+ int i, ret = 0;
blk_t block;
u64 bytenr;
u64 blocksize = ext2_fs->blocksize;
@@ -113,10 +117,19 @@ static int cache_free_extents(struct btrfs_root *root, ext2_filsys ext2_fs)
bytenr = block * blocksize;
ret = set_extent_dirty(&root->fs_info->free_space_cache,
bytenr, bytenr + blocksize - 1, 0);
- if (ret)
+ BUG_ON(ret);
+ }
+
+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ bytenr = btrfs_sb_offset(i);
+ bytenr &= ~((u64)STRIPE_LEN - 1);
+ if (bytenr >= blocksize * ext2_fs->super->s_blocks_count)
break;
+ clear_extent_dirty(&root->fs_info->free_space_cache, bytenr,
+ bytenr + STRIPE_LEN - 1, 0);
}
- return ret;
+
+ return 0;
}
static int custom_alloc_extent(struct btrfs_root *root, u64 num_bytes,
@@ -172,10 +185,26 @@ fail:
return -ENOSPC;
}
+static int intersect_with_sb(u64 bytenr, u64 num_bytes)
+{
+ int i;
+ u64 offset;
+
+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ offset = btrfs_sb_offset(i);
+ offset &= ~((u64)STRIPE_LEN - 1);
+
+ if (bytenr < offset + STRIPE_LEN &&
+ bytenr + num_bytes > offset)
+ return 1;
+ }
+ return 0;
+}
+
static int custom_free_extent(struct btrfs_root *root, u64 bytenr,
u64 num_bytes)
{
- return 0;
+ return intersect_with_sb(bytenr, num_bytes);
}
struct btrfs_extent_ops extent_ops = {
@@ -238,15 +267,17 @@ static int dir_iterate_proc(ext2_ino_t dir, int entry,
ret = btrfs_insert_dir_item(idata->trans, idata->root,
dirent->name, dirent->name_len,
idata->objectid, &location,
- filetype_conversion_table[file_type]);
+ filetype_conversion_table[file_type],
+ idata->index_cnt);
if (ret)
goto fail;
ret = btrfs_insert_inode_ref(idata->trans, idata->root,
dirent->name, dirent->name_len,
objectid, idata->objectid,
- idata->index_cnt++);
+ idata->index_cnt);
if (ret)
goto fail;
+ idata->index_cnt++;
inode_size = btrfs_stack_inode_size(idata->inode) +
dirent->name_len * 2;
btrfs_set_stack_inode_size(idata->inode, inode_size);
@@ -323,7 +354,7 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_path path;
struct btrfs_extent_item extent_item;
u32 blocksize = root->sectorsize;
- u64 nblocks;
+ u64 nbytes;
u64 bytes_used;
if (disk_bytenr == 0) {
@@ -348,9 +379,11 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
blocksize, buffer);
if (ret)
break;
- ret = btrfs_csum_file_block(trans, root, inode,
- objectid, file_pos + offset,
- buffer, blocksize);
+ ret = btrfs_csum_file_block(trans,
+ root->fs_info->csum_root,
+ disk_bytenr + num_bytes,
+ disk_bytenr + offset,
+ buffer, blocksize);
if (ret)
break;
}
@@ -375,10 +408,14 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_offset(leaf, fi, 0);
btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
+ btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
+ btrfs_set_file_extent_compression(leaf, fi, 0);
+ btrfs_set_file_extent_encryption(leaf, fi, 0);
+ btrfs_set_file_extent_other_encoding(leaf, fi, 0);
btrfs_mark_buffer_dirty(leaf);
- nblocks = btrfs_stack_inode_nblocks(inode) + num_bytes / 512;
- btrfs_set_stack_inode_nblocks(inode, nblocks);
+ nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
+ btrfs_set_stack_inode_nbytes(inode, nbytes);
bytes_used = btrfs_root_used(&root->root_item);
btrfs_set_root_used(&root->root_item, bytes_used + num_bytes);
@@ -393,6 +430,10 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
bytes_used = btrfs_super_bytes_used(&info->super_copy);
btrfs_set_super_bytes_used(&info->super_copy, bytes_used +
num_bytes);
+ ret = btrfs_update_block_group(trans, root, disk_bytenr,
+ num_bytes, 1, 0);
+ if (ret)
+ goto fail;
} else if (ret != -EEXIST) {
goto fail;
}
@@ -400,7 +441,7 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes,
leaf->start, root->root_key.objectid,
- trans->transid, objectid, file_pos);
+ trans->transid, objectid);
if (ret)
goto fail;
ret = 0;
@@ -440,13 +481,16 @@ static int block_iterate_proc(ext2_filsys ext2_fs,
struct blk_iterate_data *idata)
{
int ret;
+ int sb_region;
+ int do_barrier;
struct btrfs_root *root = idata->root;
struct btrfs_trans_handle *trans = idata->trans;
struct btrfs_block_group_cache *cache;
- u64 bytenr;
+ u64 bytenr = disk_block * root->sectorsize;
- BUG_ON(disk_block == 0);
- if ((idata->num_blocks > 0 && disk_block >= idata->boundary) ||
+ sb_region = intersect_with_sb(bytenr, root->sectorsize);
+ do_barrier = sb_region || disk_block >= idata->boundary;
+ if ((idata->num_blocks > 0 && do_barrier) ||
(file_block > idata->first_block + idata->num_blocks) ||
(disk_block != idata->disk_block + idata->num_blocks)) {
if (idata->num_blocks > 0) {
@@ -468,10 +512,14 @@ static int block_iterate_proc(ext2_filsys ext2_fs,
goto fail;
}
- bytenr = disk_block * root->sectorsize;
- cache = btrfs_lookup_block_group(root->fs_info, bytenr);
- BUG_ON(!cache);
- bytenr = cache->key.objectid + cache->key.offset;
+ if (sb_region) {
+ bytenr += STRIPE_LEN - 1;
+ bytenr &= ~((u64)STRIPE_LEN - 1);
+ } else {
+ cache = btrfs_lookup_block_group(root->fs_info, bytenr);
+ BUG_ON(!cache);
+ bytenr = cache->key.objectid + cache->key.offset;
+ }
idata->first_block = file_block;
idata->disk_block = disk_block;
@@ -925,20 +973,18 @@ static inline dev_t new_decode_dev(u32 dev)
}
static int copy_inode_item(struct btrfs_inode_item *dst,
- struct ext2_inode *src)
+ struct ext2_inode *src, u32 blocksize)
{
btrfs_set_stack_inode_generation(dst, 1);
btrfs_set_stack_inode_size(dst, src->i_size);
- btrfs_set_stack_inode_nblocks(dst, src->i_blocks);
+ btrfs_set_stack_inode_nbytes(dst, (u64)src->i_blocks * blocksize);
btrfs_set_stack_inode_block_group(dst, 0);
- btrfs_set_stack_inode_nblocks(dst, 0);
btrfs_set_stack_inode_nlink(dst, src->i_links_count);
btrfs_set_stack_inode_uid(dst, src->i_uid | (src->i_uid_high << 16));
btrfs_set_stack_inode_gid(dst, src->i_gid | (src->i_gid_high << 16));
btrfs_set_stack_inode_mode(dst, src->i_mode);
btrfs_set_stack_inode_rdev(dst, 0);
btrfs_set_stack_inode_flags(dst, 0);
- btrfs_set_stack_inode_compat_flags(dst, 0);
btrfs_set_stack_timespec_sec(&dst->atime, src->i_atime);
btrfs_set_stack_timespec_nsec(&dst->atime, 0);
btrfs_set_stack_timespec_sec(&dst->ctime, src->i_ctime);
@@ -986,7 +1032,7 @@ static int copy_single_inode(struct btrfs_trans_handle *trans,
if (ext2_inode->i_links_count == 0)
return 0;
- copy_inode_item(&btrfs_inode, ext2_inode);
+ copy_inode_item(&btrfs_inode, ext2_inode, ext2_fs->blocksize);
if (!datacsum && S_ISREG(ext2_inode->i_mode)) {
u32 flags = btrfs_stack_inode_flags(&btrfs_inode) |
BTRFS_INODE_NODATASUM;
@@ -1197,7 +1243,7 @@ static int create_ext2_image(struct btrfs_root *root, ext2_filsys ext2_fs,
btrfs_set_stack_inode_generation(&btrfs_inode, 1);
btrfs_set_stack_inode_size(&btrfs_inode, total_bytes);
btrfs_set_stack_inode_nlink(&btrfs_inode, 1);
- btrfs_set_stack_inode_nblocks(&btrfs_inode, 0);
+ btrfs_set_stack_inode_nbytes(&btrfs_inode, 0);
btrfs_set_stack_inode_mode(&btrfs_inode, S_IFREG | 0400);
btrfs_set_stack_inode_flags(&btrfs_inode, BTRFS_INODE_NODATASUM |
BTRFS_INODE_READONLY);
@@ -1330,12 +1376,13 @@ next:
btrfs_set_key_type(&location, BTRFS_INODE_ITEM_KEY);
ret = btrfs_insert_dir_item(trans, root, name, strlen(name),
btrfs_root_dirid(&root->root_item),
- &location, EXT2_FT_REG_FILE);
+ &location, EXT2_FT_REG_FILE, objectid);
if (ret)
goto fail;
ret = btrfs_insert_inode_ref(trans, root, name, strlen(name),
objectid,
- btrfs_root_dirid(&root->root_item), 0);
+ btrfs_root_dirid(&root->root_item),
+ objectid);
if (ret)
goto fail;
location.objectid = btrfs_root_dirid(&root->root_item);
@@ -1358,68 +1405,81 @@ fail:
return ret;
}
-struct btrfs_root *create_subvol(struct btrfs_root *root, const char *name)
+struct btrfs_root *link_subvol(struct btrfs_root *root, const char *base,
+ u64 root_objectid)
{
- int ret;
- u64 objectid;
- struct btrfs_key location;
- struct btrfs_root_item root_item;
struct btrfs_trans_handle *trans;
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *new_root;
- struct extent_buffer *tmp;
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ u64 dirid = btrfs_root_dirid(&root->root_item);
+ u64 index = 2;
+ char buf[64];
+ int i;
+ int ret;
+
+ path = btrfs_alloc_path();
+ BUG_ON(!path);
+
+ key.objectid = dirid;
+ key.type = BTRFS_DIR_INDEX_KEY;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ BUG_ON(ret <= 0);
+
+ if (path->slots[0] > 0) {
+ path->slots[0]--;
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (key.objectid == dirid && key.type == BTRFS_DIR_INDEX_KEY)
+ index = key.offset + 1;
+ }
+ btrfs_free_path(path);
trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);
- objectid = btrfs_super_root_dir(&fs_info->super_copy);
- ret = btrfs_find_free_objectid(trans, root, objectid, &objectid);
- if (ret)
- goto fail;
- ret = btrfs_copy_root(trans, root, root->node, &tmp, objectid);
- if (ret)
- goto fail;
- memcpy(&root_item, &root->root_item, sizeof(root_item));
- btrfs_set_root_bytenr(&root_item, tmp->start);
- btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
- free_extent_buffer(tmp);
+ key.objectid = root_objectid;
+ key.offset = (u64)-1;
+ key.type = BTRFS_ROOT_ITEM_KEY;
- location.objectid = objectid;
- location.offset = 1;
- btrfs_set_key_type(&location, BTRFS_ROOT_ITEM_KEY);
- ret = btrfs_insert_root(trans, root->fs_info->tree_root,
- &location, &root_item);
- if (ret)
- goto fail;
- location.offset = (u64)-1;
- ret = btrfs_insert_dir_item(trans, tree_root, name, strlen(name),
- btrfs_super_root_dir(&fs_info->super_copy),
- &location, BTRFS_FT_DIR);
- if (ret)
- goto fail;
- ret = btrfs_insert_inode_ref(trans, tree_root, name, strlen(name),
- objectid,
- btrfs_super_root_dir(&fs_info->super_copy),
- 0);
+ strcpy(buf, base);
+ for (i = 0; i < 1024; i++) {
+ ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf),
+ dirid, &key, BTRFS_FT_DIR, index);
+ if (ret != -EEXIST)
+ break;
+ sprintf(buf, "%s%d", base, i);
+ }
if (ret)
goto fail;
+
+ /* add the backref first */
+ ret = btrfs_add_root_ref(trans, tree_root, root_objectid,
+ BTRFS_ROOT_BACKREF_KEY,
+ root->root_key.objectid,
+ dirid, index, buf, strlen(buf));
+ BUG_ON(ret);
+
+ /* now add the forward ref */
+ ret = btrfs_add_root_ref(trans, tree_root, root->root_key.objectid,
+ BTRFS_ROOT_REF_KEY, root_objectid,
+ dirid, index, buf, strlen(buf));
+
ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret);
- new_root = btrfs_read_fs_root(fs_info, &location);
+
+ new_root = btrfs_read_fs_root(fs_info, &key);
if (!new_root || IS_ERR(new_root))
goto fail;
- trans = btrfs_start_transaction(new_root, 1);
- BUG_ON(!trans);
- ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID);
- if (ret)
- goto fail;
- ret = btrfs_commit_transaction(trans, new_root);
- BUG_ON(ret);
+
return new_root;
fail:
return NULL;
}
+
/*
* Fixup block accounting. The initial block accounting created by
* make_block_groups isn't accuracy in this case.
@@ -1572,7 +1632,7 @@ static int create_chunk_mapping(struct btrfs_trans_handle *trans,
btrfs_set_stack_chunk_length(&chunk, cache->key.offset);
btrfs_set_stack_chunk_owner(&chunk,
extent_root->root_key.objectid);
- btrfs_set_stack_chunk_stripe_len(&chunk, 64 * 1024);
+ btrfs_set_stack_chunk_stripe_len(&chunk, STRIPE_LEN);
btrfs_set_stack_chunk_type(&chunk, cache->flags);
btrfs_set_stack_chunk_io_align(&chunk, device->io_align);
btrfs_set_stack_chunk_io_width(&chunk, device->io_width);
@@ -1603,6 +1663,42 @@ err:
return ret;
}
+static int create_subvol(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 root_objectid)
+{
+ struct extent_buffer *tmp;
+ struct btrfs_root *new_root;
+ struct btrfs_key key;
+ struct btrfs_root_item root_item;
+ int ret;
+
+ ret = btrfs_copy_root(trans, root, root->node, &tmp,
+ root_objectid);
+ BUG_ON(ret);
+
+ memcpy(&root_item, &root->root_item, sizeof(root_item));
+ btrfs_set_root_bytenr(&root_item, tmp->start);
+ btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
+ btrfs_set_root_generation(&root_item, trans->transid);
+ free_extent_buffer(tmp);
+
+ key.objectid = root_objectid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = trans->transid;
+ ret = btrfs_insert_root(trans, root->fs_info->tree_root,
+ &key, &root_item);
+
+ key.offset = (u64)-1;
+ new_root = btrfs_read_fs_root(root->fs_info, &key);
+ BUG_ON(!new_root || IS_ERR(new_root));
+
+ ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID);
+ BUG_ON(ret);
+
+ btrfs_free_fs_root(root->fs_info, new_root);
+ return 0;
+}
+
static int init_btrfs(struct btrfs_root *root)
{
int ret;
@@ -1629,7 +1725,7 @@ static int init_btrfs(struct btrfs_root *root)
location.offset = (u64)-1;
ret = btrfs_insert_dir_item(trans, fs_info->tree_root, "default", 7,
btrfs_super_root_dir(&fs_info->super_copy),
- &location, BTRFS_FT_DIR);
+ &location, BTRFS_FT_DIR, 0);
if (ret)
goto err;
ret = btrfs_insert_inode_ref(trans, fs_info->tree_root, "default", 7,
@@ -1639,6 +1735,14 @@ static int init_btrfs(struct btrfs_root *root)
goto err;
btrfs_set_root_dirid(&fs_info->fs_root->root_item,
BTRFS_FIRST_FREE_OBJECTID);
+
+ /* subvol for ext2 image file */
+ ret = create_subvol(trans, root, EXT2_IMAGE_SUBVOL_OBJECTID);
+ BUG_ON(ret);
+ /* subvol for data relocation */
+ ret = create_subvol(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
+ BUG_ON(ret);
+
ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret);
err:
@@ -1670,7 +1774,7 @@ static int migrate_super_block(int fd, u64 old_bytenr, u32 sectorsize)
BUG_ON(btrfs_super_bytenr(super) != old_bytenr);
btrfs_set_super_bytenr(super, BTRFS_SUPER_INFO_OFFSET);
- csum_tree_block(NULL, buf, 0);
+ csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
ret = pwrite(fd, buf->data, sectorsize, BTRFS_SUPER_INFO_OFFSET);
if (ret != sectorsize)
goto fail;
@@ -1754,7 +1858,7 @@ static int prepare_system_chunk(int fd, u64 sb_bytenr, u32 sectorsize)
if (ret)
goto fail;
- csum_tree_block(NULL, buf, 0);
+ csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
ret = pwrite(fd, buf->data, sectorsize, sb_bytenr);
if (ret != sectorsize)
goto fail;
@@ -1770,7 +1874,7 @@ fail:
static int relocate_one_reference(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 extent_start, u64 extent_size,
- u64 objectid, u64 offset,
+ u64 objectid, struct btrfs_key *leaf_key,
struct extent_io_tree *reloc_tree)
{
struct extent_buffer *leaf;
@@ -1780,30 +1884,56 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
struct btrfs_inode_item inode;
struct blk_iterate_data data;
u64 bytenr;
+ u64 offset;
u64 num_bytes;
u64 cur_offset;
u64 new_pos;
- u64 nblocks;
+ u64 nbytes;
u64 root_gen;
u64 root_owner;
u64 sector_end;
+ u32 nritems;
u32 sectorsize = root->sectorsize;
unsigned long ptr;
+ int found = 0;
+ int datacsum;
int fd;
int ret;
+ memcpy(&key, leaf_key, sizeof(key));
+ if (key.objectid < objectid ||
+ (key.objectid == objectid &&
+ key.type < BTRFS_EXTENT_DATA_KEY)) {
+ key.objectid = objectid;
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = 0;
+ }
btrfs_init_path(&path);
- ret = btrfs_lookup_file_extent(trans, root, &path,
- objectid, offset, -1);
- if (ret)
+ ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
+ if (ret < 0)
goto fail;
leaf = path.nodes[0];
- fi = btrfs_item_ptr(leaf, path.slots[0],
- struct btrfs_file_extent_item);
- /* the extent may be referenced by old snapshot */
- if (extent_start != btrfs_file_extent_disk_bytenr(leaf, fi) ||
- extent_size != btrfs_file_extent_disk_num_bytes(leaf, fi)) {
+ nritems = btrfs_header_nritems(leaf);
+ while (1) {
+ if (path.slots[0] >= nritems)
+ break;
+ btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
+ if (key.objectid != objectid ||
+ key.type != BTRFS_EXTENT_DATA_KEY)
+ break;
+ fi = btrfs_item_ptr(leaf, path.slots[0],
+ struct btrfs_file_extent_item);
+ if (extent_start == btrfs_file_extent_disk_bytenr(leaf, fi) &&
+ extent_size == btrfs_file_extent_disk_num_bytes(leaf, fi)) {
+ offset = key.offset;
+ found = 1;
+ break;
+ }
+ path.slots[0]++;
+ }
+
+ if (!found) {
ret = 1;
goto fail;
}
@@ -1817,9 +1947,9 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
if (ret)
goto fail;
- ret = btrfs_free_extent(trans, root, extent_start, extent_size,
- leaf->start, root_owner, root_gen, objectid,
- offset, 0);
+ ret = btrfs_free_extent(trans, root,
+ extent_start, extent_size, leaf->start,
+ root_owner, root_gen, objectid, 0);
if (ret)
goto fail;
@@ -1838,8 +1968,9 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
btrfs_release_path(root, &path);
BUG_ON(num_bytes & (sectorsize - 1));
- nblocks = btrfs_stack_inode_nblocks(&inode) - num_bytes / 512;
- btrfs_set_stack_inode_nblocks(&inode, nblocks);
+ nbytes = btrfs_stack_inode_nbytes(&inode) - num_bytes;
+ btrfs_set_stack_inode_nbytes(&inode, nbytes);
+ datacsum = !(btrfs_stack_inode_flags(&inode) & BTRFS_INODE_NODATASUM);
data = (struct blk_iterate_data) {
.trans = trans,
@@ -1850,7 +1981,7 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
.disk_block = 0,
.num_blocks = 0,
.boundary = (u64)-1,
- .checksum = 0,
+ .checksum = datacsum,
.errcode = 0,
};
@@ -1926,25 +2057,46 @@ static int relocate_extents_range(struct btrfs_root *fs_root,
{
struct btrfs_fs_info *info = fs_root->fs_info;
struct btrfs_root *extent_root = info->extent_root;
- struct btrfs_root *cur_root;
+ struct btrfs_root *cur_root = NULL;
struct btrfs_trans_handle *trans;
struct btrfs_extent_ref *ref_item;
struct extent_buffer *leaf;
struct btrfs_key key;
+ struct btrfs_key leaf_key;
struct btrfs_path path;
struct extent_io_tree reloc_tree;
u64 cur_byte;
u64 num_bytes;
u64 ref_root;
u64 ref_owner;
- u64 ref_offset;
u64 num_refs;
+ u64 leaf_start;
int pass = 0;
int ret;
int found;
btrfs_init_path(&path);
extent_io_tree_init(&reloc_tree);
+
+ key.objectid = start_byte;
+ key.offset = 0;
+ key.type = BTRFS_EXTENT_ITEM_KEY;
+ ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
+ if (ret < 0)
+ goto fail;
+ if (ret > 0) {
+ ret = btrfs_previous_item(extent_root, &path, 0,
+ BTRFS_EXTENT_ITEM_KEY);
+ if (ret < 0)
+ goto fail;
+ if (ret == 0) {
+ leaf = path.nodes[0];
+ btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
+ if (key.objectid + key.offset > start_byte)
+ start_byte = key.objectid;
+ }
+ }
+ btrfs_release_path(extent_root, &path);
again:
cur_root = (pass % 2 == 0) ? ext2_root : fs_root;
num_refs = 0;
@@ -2005,7 +2157,7 @@ next:
struct btrfs_extent_ref);
ref_root = btrfs_ref_root(leaf, ref_item);
ref_owner = btrfs_ref_objectid(leaf, ref_item);
- ref_offset = btrfs_ref_offset(leaf, ref_item);
+ leaf_start = key.offset;
num_refs++;
BUG_ON(ref_owner < BTRFS_FIRST_FREE_OBJECTID);
@@ -2018,9 +2170,16 @@ next:
if (!found)
goto next;
+ leaf = read_tree_block(cur_root, leaf_start,
+ btrfs_level_size(cur_root, 0), 0);
+ BUG_ON(!leaf);
+ BUG_ON(btrfs_header_level(leaf) != 0);
+ btrfs_item_key_to_cpu(leaf, &leaf_key, 0);
+ free_extent_buffer(leaf);
+
ret = relocate_one_reference(trans, cur_root, cur_byte,
num_bytes, ref_owner,
- ref_offset, &reloc_tree);
+ &leaf_key, &reloc_tree);
if (ret < 0)
goto fail;
@@ -2056,7 +2215,7 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root,
struct btrfs_root *ext2_root)
{
struct btrfs_block_group_cache *cache;
- int ret = 0;
+ int i, ret = 0;
u64 offset = 0;
u64 end_byte;
@@ -2075,6 +2234,16 @@ static int cleanup_sys_chunk(struct btrfs_root *fs_root,
}
offset = end_byte;
}
+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ offset = btrfs_sb_offset(i);
+ offset &= ~((u64)STRIPE_LEN - 1);
+
+ ret = relocate_extents_range(fs_root, ext2_root,
+ offset, offset + STRIPE_LEN);
+ if (ret)
+ goto fail;
+ }
+ ret = 0;
fail:
return ret;
}
@@ -2234,7 +2403,7 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
}
root->fs_info->extent_ops = &extent_ops;
/* recover block allocation bitmap */
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 7; i++) {
blocks[i] /= blocksize;
ext2_free_block(ext2_fs, blocks[i]);
}
@@ -2243,11 +2412,6 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
fprintf(stderr, "unable to setup the root tree\n");
goto fail;
}
- ext2_root = create_subvol(root, "ext2_saved");
- if (!ext2_root) {
- fprintf(stderr, "unable to create subvol\n");
- goto fail;
- }
printf("creating btrfs metadata.\n");
ret = copy_inodes(root, ext2_fs, datacsum, packing, noxattr);
if (ret) {
@@ -2255,6 +2419,11 @@ int do_convert(const char *devname, int datacsum, int packing, int noxattr)
goto fail;
}
printf("creating ext2fs image file.\n");
+ ext2_root = link_subvol(root, "ext2_saved", EXT2_IMAGE_SUBVOL_OBJECTID);
+ if (!ext2_root) {
+ fprintf(stderr, "unable to create subvol\n");
+ goto fail;
+ }
ret = create_ext2_image(ext2_root, ext2_fs, "image");
if (ret) {
fprintf(stderr, "error during create_ext2_image %d\n", ret);
@@ -2401,21 +2570,14 @@ int do_rollback(const char *devname, int force)
}
btrfs_init_path(&path);
- name = "ext2_saved";
- root_dir = btrfs_super_root_dir(&root->fs_info->super_copy);
- dir = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, &path,
- root_dir, name, strlen(name), 0);
- if (!dir || IS_ERR(dir)) {
- fprintf(stderr, "unable to find subvol %s\n", name);
- goto fail;
- }
- leaf = path.nodes[0];
- btrfs_dir_item_key_to_cpu(leaf, dir, &key);
- btrfs_release_path(root->fs_info->tree_root, &path);
+ key.objectid = EXT2_IMAGE_SUBVOL_OBJECTID;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
ext2_root = btrfs_read_fs_root(root->fs_info, &key);
if (!ext2_root || IS_ERR(ext2_root)) {
- fprintf(stderr, "unable to open subvol %s\n", name);
+ fprintf(stderr, "unable to open subvol %llu\n",
+ key.objectid);
goto fail;
}
@@ -2485,7 +2647,8 @@ int do_rollback(const char *devname, int force)
cache2 = btrfs_lookup_block_group(root->fs_info,
offset + num_bytes - 1);
if (!cache1 || cache1 != cache2 ||
- !(cache1->flags & BTRFS_BLOCK_GROUP_SYSTEM))
+ (!(cache1->flags & BTRFS_BLOCK_GROUP_SYSTEM) &&
+ !intersect_with_sb(offset, num_bytes)))
break;
set_extent_bits(&io_tree, offset, offset + num_bytes - 1,