From 3a724cbde0f3e9ff94bff787a9185a030c7f7073 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Fri, 27 Jan 2017 15:47:17 +0100 Subject: [PATCH] btrfs-progs: convert: move implementation for interal conversion API to own file Signed-off-by: David Sterba --- Makefile.in | 8 +- convert/main.c | 246 ---------------------------------------- convert/source-fs.c | 270 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+), 250 deletions(-) create mode 100644 convert/source-fs.c diff --git a/Makefile.in b/Makefile.in index 4d9603cc..ddd1e93a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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) \ $(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] $@" $(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) 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] $@" $(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) dir-test: $(objects) $(libs) dir-test.o diff --git a/convert/main.c b/convert/main.c index 105c4c12..aa0d805b 100644 --- a/convert/main.c +++ b/convert/main.c @@ -70,20 +70,6 @@ static int after_copied_inodes(void *p) 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, struct btrfs_root *root, int datacsum, 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); } -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, struct btrfs_root *root, u64 disk_bytenr, u64 num_bytes) @@ -192,177 +117,6 @@ static int csum_disk_extent(struct btrfs_trans_handle *trans, 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, struct btrfs_root *root, struct cache_tree *used, diff --git a/convert/source-fs.c b/convert/source-fs.c new file mode 100644 index 00000000..f2952777 --- /dev/null +++ b/convert/source-fs.c @@ -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 +#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; +} +