summaryrefslogtreecommitdiff
path: root/convert.c
diff options
context:
space:
mode:
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,