btrfs-progs: convert: move implementation for interal conversion API to own file
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
03c085861b
commit
3a724cbde0
|
@ -404,17 +404,17 @@ btrfs-image.static: $(static_objects) image/main.static.o $(static_libbtrfs_obje
|
||||||
$(Q)$(CC) $(STATIC_CFLAGS) -o $@ image/main.static.o $(static_objects) \
|
$(Q)$(CC) $(STATIC_CFLAGS) -o $@ image/main.static.o $(static_objects) \
|
||||||
$(static_libbtrfs_objects) $(STATIC_LDFLAGS) $(STATIC_LIBS)
|
$(static_libbtrfs_objects) $(STATIC_LDFLAGS) $(STATIC_LIBS)
|
||||||
|
|
||||||
btrfs-convert: $(objects) $(libs_static) convert/main.o convert/common.o convert/source-ext2.o
|
btrfs-convert: $(objects) $(libs_static) convert/main.o convert/common.o convert/source-fs.o convert/source-ext2.o
|
||||||
@echo " [LD] $@"
|
@echo " [LD] $@"
|
||||||
$(Q)$(CC) $(CFLAGS) -I$(TOPDIR)/convert -o btrfs-convert $(objects) \
|
$(Q)$(CC) $(CFLAGS) -I$(TOPDIR)/convert -o btrfs-convert $(objects) \
|
||||||
convert/main.o convert/common.o convert/source-ext2.o $(libs_static) \
|
convert/main.o convert/common.o convert/source-fs.o convert/source-ext2.o $(libs_static) \
|
||||||
$(LDFLAGS) $(btrfs_convert_libs) $(LIBS)
|
$(LDFLAGS) $(btrfs_convert_libs) $(LIBS)
|
||||||
|
|
||||||
btrfs-convert.static: $(static_objects) convert/main.static.o convert/common.static.o \
|
btrfs-convert.static: $(static_objects) convert/main.static.o convert/common.static.o \
|
||||||
convert/source-ext2.static. o $(static_libbtrfs_objects)
|
convert/source-fs.static.o convert/source-ext2.static. o $(static_libbtrfs_objects)
|
||||||
@echo " [LD] $@"
|
@echo " [LD] $@"
|
||||||
$(Q)$(CC) $(STATIC_CFLAGS) -o $@ convert/main.static.o convert/common.static.o \
|
$(Q)$(CC) $(STATIC_CFLAGS) -o $@ convert/main.static.o convert/common.static.o \
|
||||||
convert/source-ext2.static.o $(static_objects) \
|
convert/source-fs.static.o convert/source-ext2.static.o $(static_objects) \
|
||||||
$(static_libbtrfs_objects) $(STATIC_LDFLAGS) $(btrfs_convert_libs) $(STATIC_LIBS)
|
$(static_libbtrfs_objects) $(STATIC_LDFLAGS) $(btrfs_convert_libs) $(STATIC_LIBS)
|
||||||
|
|
||||||
dir-test: $(objects) $(libs) dir-test.o
|
dir-test: $(objects) $(libs) dir-test.o
|
||||||
|
|
246
convert/main.c
246
convert/main.c
|
@ -70,20 +70,6 @@ static int after_copied_inodes(void *p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_convert_context(struct btrfs_convert_context *cctx)
|
|
||||||
{
|
|
||||||
cache_tree_init(&cctx->used);
|
|
||||||
cache_tree_init(&cctx->data_chunks);
|
|
||||||
cache_tree_init(&cctx->free);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clean_convert_context(struct btrfs_convert_context *cctx)
|
|
||||||
{
|
|
||||||
free_extent_cache_tree(&cctx->used);
|
|
||||||
free_extent_cache_tree(&cctx->data_chunks);
|
|
||||||
free_extent_cache_tree(&cctx->free);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int copy_inodes(struct btrfs_convert_context *cctx,
|
static inline int copy_inodes(struct btrfs_convert_context *cctx,
|
||||||
struct btrfs_root *root, int datacsum,
|
struct btrfs_root *root, int datacsum,
|
||||||
int packing, int noxattr, struct task_ctx *p)
|
int packing, int noxattr, struct task_ctx *p)
|
||||||
|
@ -102,67 +88,6 @@ static inline int convert_check_state(struct btrfs_convert_context *cctx)
|
||||||
return cctx->convert_ops->check_state(cctx);
|
return cctx->convert_ops->check_state(cctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)BTRFS_STRIPE_LEN - 1);
|
|
||||||
|
|
||||||
if (bytenr < offset + BTRFS_STRIPE_LEN &&
|
|
||||||
bytenr + num_bytes > offset)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int convert_insert_dirent(struct btrfs_trans_handle *trans,
|
|
||||||
struct btrfs_root *root,
|
|
||||||
const char *name, size_t name_len,
|
|
||||||
u64 dir, u64 objectid,
|
|
||||||
u8 file_type, u64 index_cnt,
|
|
||||||
struct btrfs_inode_item *inode)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
u64 inode_size;
|
|
||||||
struct btrfs_key location = {
|
|
||||||
.objectid = objectid,
|
|
||||||
.offset = 0,
|
|
||||||
.type = BTRFS_INODE_ITEM_KEY,
|
|
||||||
};
|
|
||||||
|
|
||||||
ret = btrfs_insert_dir_item(trans, root, name, name_len,
|
|
||||||
dir, &location, file_type, index_cnt);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = btrfs_insert_inode_ref(trans, root, name, name_len,
|
|
||||||
objectid, dir, index_cnt);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
inode_size = btrfs_stack_inode_size(inode) + name_len * 2;
|
|
||||||
btrfs_set_stack_inode_size(inode, inode_size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int read_disk_extent(struct btrfs_root *root, u64 bytenr,
|
|
||||||
u32 num_bytes, char *buffer)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct btrfs_fs_devices *fs_devs = root->fs_info->fs_devices;
|
|
||||||
|
|
||||||
ret = pread(fs_devs->latest_bdev, buffer, num_bytes, bytenr);
|
|
||||||
if (ret != num_bytes)
|
|
||||||
goto fail;
|
|
||||||
ret = 0;
|
|
||||||
fail:
|
|
||||||
if (ret > 0)
|
|
||||||
ret = -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int csum_disk_extent(struct btrfs_trans_handle *trans,
|
static int csum_disk_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
u64 disk_bytenr, u64 num_bytes)
|
u64 disk_bytenr, u64 num_bytes)
|
||||||
|
@ -192,177 +117,6 @@ static int csum_disk_extent(struct btrfs_trans_handle *trans,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_blk_iterate_data(struct blk_iterate_data *data,
|
|
||||||
struct btrfs_trans_handle *trans,
|
|
||||||
struct btrfs_root *root,
|
|
||||||
struct btrfs_inode_item *inode,
|
|
||||||
u64 objectid, int checksum)
|
|
||||||
{
|
|
||||||
struct btrfs_key key;
|
|
||||||
|
|
||||||
data->trans = trans;
|
|
||||||
data->root = root;
|
|
||||||
data->inode = inode;
|
|
||||||
data->objectid = objectid;
|
|
||||||
data->first_block = 0;
|
|
||||||
data->disk_block = 0;
|
|
||||||
data->num_blocks = 0;
|
|
||||||
data->boundary = (u64)-1;
|
|
||||||
data->checksum = checksum;
|
|
||||||
data->errcode = 0;
|
|
||||||
|
|
||||||
key.objectid = CONV_IMAGE_SUBVOL_OBJECTID;
|
|
||||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
|
||||||
key.offset = (u64)-1;
|
|
||||||
data->convert_root = btrfs_read_fs_root(root->fs_info, &key);
|
|
||||||
/* Impossible as we just opened it before */
|
|
||||||
BUG_ON(!data->convert_root || IS_ERR(data->convert_root));
|
|
||||||
data->convert_ino = BTRFS_FIRST_FREE_OBJECTID + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Record a file extent in original filesystem into btrfs one.
|
|
||||||
* The special point is, old disk_block can point to a reserved range.
|
|
||||||
* So here, we don't use disk_block directly but search convert_root
|
|
||||||
* to get the real disk_bytenr.
|
|
||||||
*/
|
|
||||||
int record_file_blocks(struct blk_iterate_data *data,
|
|
||||||
u64 file_block, u64 disk_block, u64 num_blocks)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
struct btrfs_root *root = data->root;
|
|
||||||
struct btrfs_root *convert_root = data->convert_root;
|
|
||||||
struct btrfs_path path;
|
|
||||||
u64 file_pos = file_block * root->sectorsize;
|
|
||||||
u64 old_disk_bytenr = disk_block * root->sectorsize;
|
|
||||||
u64 num_bytes = num_blocks * root->sectorsize;
|
|
||||||
u64 cur_off = old_disk_bytenr;
|
|
||||||
|
|
||||||
/* Hole, pass it to record_file_extent directly */
|
|
||||||
if (old_disk_bytenr == 0)
|
|
||||||
return btrfs_record_file_extent(data->trans, root,
|
|
||||||
data->objectid, data->inode, file_pos, 0,
|
|
||||||
num_bytes);
|
|
||||||
|
|
||||||
btrfs_init_path(&path);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Search real disk bytenr from convert root
|
|
||||||
*/
|
|
||||||
while (cur_off < old_disk_bytenr + num_bytes) {
|
|
||||||
struct btrfs_key key;
|
|
||||||
struct btrfs_file_extent_item *fi;
|
|
||||||
struct extent_buffer *node;
|
|
||||||
int slot;
|
|
||||||
u64 extent_disk_bytenr;
|
|
||||||
u64 extent_num_bytes;
|
|
||||||
u64 real_disk_bytenr;
|
|
||||||
u64 cur_len;
|
|
||||||
|
|
||||||
key.objectid = data->convert_ino;
|
|
||||||
key.type = BTRFS_EXTENT_DATA_KEY;
|
|
||||||
key.offset = cur_off;
|
|
||||||
|
|
||||||
ret = btrfs_search_slot(NULL, convert_root, &key, &path, 0, 0);
|
|
||||||
if (ret < 0)
|
|
||||||
break;
|
|
||||||
if (ret > 0) {
|
|
||||||
ret = btrfs_previous_item(convert_root, &path,
|
|
||||||
data->convert_ino,
|
|
||||||
BTRFS_EXTENT_DATA_KEY);
|
|
||||||
if (ret < 0)
|
|
||||||
break;
|
|
||||||
if (ret > 0) {
|
|
||||||
ret = -ENOENT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node = path.nodes[0];
|
|
||||||
slot = path.slots[0];
|
|
||||||
btrfs_item_key_to_cpu(node, &key, slot);
|
|
||||||
BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY ||
|
|
||||||
key.objectid != data->convert_ino ||
|
|
||||||
key.offset > cur_off);
|
|
||||||
fi = btrfs_item_ptr(node, slot, struct btrfs_file_extent_item);
|
|
||||||
extent_disk_bytenr = btrfs_file_extent_disk_bytenr(node, fi);
|
|
||||||
extent_num_bytes = btrfs_file_extent_num_bytes(node, fi);
|
|
||||||
BUG_ON(cur_off - key.offset >= extent_num_bytes);
|
|
||||||
btrfs_release_path(&path);
|
|
||||||
|
|
||||||
if (extent_disk_bytenr)
|
|
||||||
real_disk_bytenr = cur_off - key.offset +
|
|
||||||
extent_disk_bytenr;
|
|
||||||
else
|
|
||||||
real_disk_bytenr = 0;
|
|
||||||
cur_len = min(key.offset + extent_num_bytes,
|
|
||||||
old_disk_bytenr + num_bytes) - cur_off;
|
|
||||||
ret = btrfs_record_file_extent(data->trans, data->root,
|
|
||||||
data->objectid, data->inode, file_pos,
|
|
||||||
real_disk_bytenr, cur_len);
|
|
||||||
if (ret < 0)
|
|
||||||
break;
|
|
||||||
cur_off += cur_len;
|
|
||||||
file_pos += cur_len;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* No need to care about csum
|
|
||||||
* As every byte of old fs image is calculated for csum, no
|
|
||||||
* need to waste CPU cycles now.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
btrfs_release_path(&path);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int block_iterate_proc(u64 disk_block, u64 file_block,
|
|
||||||
struct blk_iterate_data *idata)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
int sb_region;
|
|
||||||
int do_barrier;
|
|
||||||
struct btrfs_root *root = idata->root;
|
|
||||||
struct btrfs_block_group_cache *cache;
|
|
||||||
u64 bytenr = disk_block * root->sectorsize;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
ret = record_file_blocks(idata, idata->first_block,
|
|
||||||
idata->disk_block,
|
|
||||||
idata->num_blocks);
|
|
||||||
if (ret)
|
|
||||||
goto fail;
|
|
||||||
idata->first_block += idata->num_blocks;
|
|
||||||
idata->num_blocks = 0;
|
|
||||||
}
|
|
||||||
if (file_block > idata->first_block) {
|
|
||||||
ret = record_file_blocks(idata, idata->first_block,
|
|
||||||
0, file_block - idata->first_block);
|
|
||||||
if (ret)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sb_region) {
|
|
||||||
bytenr += BTRFS_STRIPE_LEN - 1;
|
|
||||||
bytenr &= ~((u64)BTRFS_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;
|
|
||||||
idata->boundary = bytenr / root->sectorsize;
|
|
||||||
}
|
|
||||||
idata->num_blocks++;
|
|
||||||
fail:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_image_file_range(struct btrfs_trans_handle *trans,
|
static int create_image_file_range(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct cache_tree *used,
|
struct cache_tree *used,
|
||||||
|
|
270
convert/source-fs.c
Normal file
270
convert/source-fs.c
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public
|
||||||
|
* License v2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public
|
||||||
|
* License along with this program; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 021110-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kerncompat.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "internal.h"
|
||||||
|
#include "disk-io.h"
|
||||||
|
#include "volumes.h"
|
||||||
|
#include "convert/common.h"
|
||||||
|
#include "convert/source-fs.h"
|
||||||
|
|
||||||
|
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)BTRFS_STRIPE_LEN - 1);
|
||||||
|
|
||||||
|
if (bytenr < offset + BTRFS_STRIPE_LEN &&
|
||||||
|
bytenr + num_bytes > offset)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_convert_context(struct btrfs_convert_context *cctx)
|
||||||
|
{
|
||||||
|
cache_tree_init(&cctx->used);
|
||||||
|
cache_tree_init(&cctx->data_chunks);
|
||||||
|
cache_tree_init(&cctx->free);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clean_convert_context(struct btrfs_convert_context *cctx)
|
||||||
|
{
|
||||||
|
free_extent_cache_tree(&cctx->used);
|
||||||
|
free_extent_cache_tree(&cctx->data_chunks);
|
||||||
|
free_extent_cache_tree(&cctx->free);
|
||||||
|
}
|
||||||
|
|
||||||
|
int block_iterate_proc(u64 disk_block, u64 file_block,
|
||||||
|
struct blk_iterate_data *idata)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int sb_region;
|
||||||
|
int do_barrier;
|
||||||
|
struct btrfs_root *root = idata->root;
|
||||||
|
struct btrfs_block_group_cache *cache;
|
||||||
|
u64 bytenr = disk_block * root->sectorsize;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
ret = record_file_blocks(idata, idata->first_block,
|
||||||
|
idata->disk_block,
|
||||||
|
idata->num_blocks);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
idata->first_block += idata->num_blocks;
|
||||||
|
idata->num_blocks = 0;
|
||||||
|
}
|
||||||
|
if (file_block > idata->first_block) {
|
||||||
|
ret = record_file_blocks(idata, idata->first_block,
|
||||||
|
0, file_block - idata->first_block);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb_region) {
|
||||||
|
bytenr += BTRFS_STRIPE_LEN - 1;
|
||||||
|
bytenr &= ~((u64)BTRFS_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;
|
||||||
|
idata->boundary = bytenr / root->sectorsize;
|
||||||
|
}
|
||||||
|
idata->num_blocks++;
|
||||||
|
fail:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_blk_iterate_data(struct blk_iterate_data *data,
|
||||||
|
struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_inode_item *inode,
|
||||||
|
u64 objectid, int checksum)
|
||||||
|
{
|
||||||
|
struct btrfs_key key;
|
||||||
|
|
||||||
|
data->trans = trans;
|
||||||
|
data->root = root;
|
||||||
|
data->inode = inode;
|
||||||
|
data->objectid = objectid;
|
||||||
|
data->first_block = 0;
|
||||||
|
data->disk_block = 0;
|
||||||
|
data->num_blocks = 0;
|
||||||
|
data->boundary = (u64)-1;
|
||||||
|
data->checksum = checksum;
|
||||||
|
data->errcode = 0;
|
||||||
|
|
||||||
|
key.objectid = CONV_IMAGE_SUBVOL_OBJECTID;
|
||||||
|
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||||
|
key.offset = (u64)-1;
|
||||||
|
data->convert_root = btrfs_read_fs_root(root->fs_info, &key);
|
||||||
|
/* Impossible as we just opened it before */
|
||||||
|
BUG_ON(!data->convert_root || IS_ERR(data->convert_root));
|
||||||
|
data->convert_ino = BTRFS_FIRST_FREE_OBJECTID + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int convert_insert_dirent(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
const char *name, size_t name_len,
|
||||||
|
u64 dir, u64 objectid,
|
||||||
|
u8 file_type, u64 index_cnt,
|
||||||
|
struct btrfs_inode_item *inode)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u64 inode_size;
|
||||||
|
struct btrfs_key location = {
|
||||||
|
.objectid = objectid,
|
||||||
|
.offset = 0,
|
||||||
|
.type = BTRFS_INODE_ITEM_KEY,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = btrfs_insert_dir_item(trans, root, name, name_len,
|
||||||
|
dir, &location, file_type, index_cnt);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = btrfs_insert_inode_ref(trans, root, name, name_len,
|
||||||
|
objectid, dir, index_cnt);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
inode_size = btrfs_stack_inode_size(inode) + name_len * 2;
|
||||||
|
btrfs_set_stack_inode_size(inode, inode_size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_disk_extent(struct btrfs_root *root, u64 bytenr,
|
||||||
|
u32 num_bytes, char *buffer)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct btrfs_fs_devices *fs_devs = root->fs_info->fs_devices;
|
||||||
|
|
||||||
|
ret = pread(fs_devs->latest_bdev, buffer, num_bytes, bytenr);
|
||||||
|
if (ret != num_bytes)
|
||||||
|
goto fail;
|
||||||
|
ret = 0;
|
||||||
|
fail:
|
||||||
|
if (ret > 0)
|
||||||
|
ret = -1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record a file extent in original filesystem into btrfs one.
|
||||||
|
* The special point is, old disk_block can point to a reserved range.
|
||||||
|
* So here, we don't use disk_block directly but search convert_root
|
||||||
|
* to get the real disk_bytenr.
|
||||||
|
*/
|
||||||
|
int record_file_blocks(struct blk_iterate_data *data,
|
||||||
|
u64 file_block, u64 disk_block, u64 num_blocks)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct btrfs_root *root = data->root;
|
||||||
|
struct btrfs_root *convert_root = data->convert_root;
|
||||||
|
struct btrfs_path path;
|
||||||
|
u64 file_pos = file_block * root->sectorsize;
|
||||||
|
u64 old_disk_bytenr = disk_block * root->sectorsize;
|
||||||
|
u64 num_bytes = num_blocks * root->sectorsize;
|
||||||
|
u64 cur_off = old_disk_bytenr;
|
||||||
|
|
||||||
|
/* Hole, pass it to record_file_extent directly */
|
||||||
|
if (old_disk_bytenr == 0)
|
||||||
|
return btrfs_record_file_extent(data->trans, root,
|
||||||
|
data->objectid, data->inode, file_pos, 0,
|
||||||
|
num_bytes);
|
||||||
|
|
||||||
|
btrfs_init_path(&path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search real disk bytenr from convert root
|
||||||
|
*/
|
||||||
|
while (cur_off < old_disk_bytenr + num_bytes) {
|
||||||
|
struct btrfs_key key;
|
||||||
|
struct btrfs_file_extent_item *fi;
|
||||||
|
struct extent_buffer *node;
|
||||||
|
int slot;
|
||||||
|
u64 extent_disk_bytenr;
|
||||||
|
u64 extent_num_bytes;
|
||||||
|
u64 real_disk_bytenr;
|
||||||
|
u64 cur_len;
|
||||||
|
|
||||||
|
key.objectid = data->convert_ino;
|
||||||
|
key.type = BTRFS_EXTENT_DATA_KEY;
|
||||||
|
key.offset = cur_off;
|
||||||
|
|
||||||
|
ret = btrfs_search_slot(NULL, convert_root, &key, &path, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
if (ret > 0) {
|
||||||
|
ret = btrfs_previous_item(convert_root, &path,
|
||||||
|
data->convert_ino,
|
||||||
|
BTRFS_EXTENT_DATA_KEY);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
if (ret > 0) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = path.nodes[0];
|
||||||
|
slot = path.slots[0];
|
||||||
|
btrfs_item_key_to_cpu(node, &key, slot);
|
||||||
|
BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY ||
|
||||||
|
key.objectid != data->convert_ino ||
|
||||||
|
key.offset > cur_off);
|
||||||
|
fi = btrfs_item_ptr(node, slot, struct btrfs_file_extent_item);
|
||||||
|
extent_disk_bytenr = btrfs_file_extent_disk_bytenr(node, fi);
|
||||||
|
extent_num_bytes = btrfs_file_extent_num_bytes(node, fi);
|
||||||
|
BUG_ON(cur_off - key.offset >= extent_num_bytes);
|
||||||
|
btrfs_release_path(&path);
|
||||||
|
|
||||||
|
if (extent_disk_bytenr)
|
||||||
|
real_disk_bytenr = cur_off - key.offset +
|
||||||
|
extent_disk_bytenr;
|
||||||
|
else
|
||||||
|
real_disk_bytenr = 0;
|
||||||
|
cur_len = min(key.offset + extent_num_bytes,
|
||||||
|
old_disk_bytenr + num_bytes) - cur_off;
|
||||||
|
ret = btrfs_record_file_extent(data->trans, data->root,
|
||||||
|
data->objectid, data->inode, file_pos,
|
||||||
|
real_disk_bytenr, cur_len);
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
cur_off += cur_len;
|
||||||
|
file_pos += cur_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No need to care about csum
|
||||||
|
* As every byte of old fs image is calculated for csum, no
|
||||||
|
* need to waste CPU cycles now.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
btrfs_release_path(&path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue