From patchwork Fri Nov 20 03:24:24 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 7664281 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9D18E9F96D for ; Fri, 20 Nov 2015 03:27:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 979142045B for ; Fri, 20 Nov 2015 03:27:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9D5E120459 for ; Fri, 20 Nov 2015 03:27:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1161937AbbKTD1V (ORCPT ); Thu, 19 Nov 2015 22:27:21 -0500 Received: from cn.fujitsu.com ([59.151.112.132]:31138 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1161906AbbKTD1S (ORCPT ); Thu, 19 Nov 2015 22:27:18 -0500 X-IronPort-AV: E=Sophos;i="5.20,242,1444665600"; d="scan'208";a="654843" Received: from unknown (HELO tang.cn.fujitsu.com) ([10.167.250.3]) by heian.cn.fujitsu.com with ESMTP; 20 Nov 2015 11:27:05 +0800 Received: from localhost.localdomain (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id tAK3PqdT022290 for ; Fri, 20 Nov 2015 11:26:31 +0800 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH 20/25] btrfs-progs: Enhance record_file_blocks to handle reserved ranges Date: Fri, 20 Nov 2015 11:24:24 +0800 Message-Id: <1447989869-24739-21-git-send-email-quwenruo@cn.fujitsu.com> X-Mailer: git-send-email 2.6.2 In-Reply-To: <1447989869-24739-1-git-send-email-quwenruo@cn.fujitsu.com> References: <1447989869-24739-1-git-send-email-quwenruo@cn.fujitsu.com> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Enhance record_file_blocks() function to handle reserved ranges. Unlike most of file extents, ext* data in reserved ranges are not mapped on disk with 1:1 bytenr. So we can't use bytenr directly. But thanks for calling create_ext2_image_v2() before copying inodes, we have a image in convert subvolume as a logical <-> disk bytenr mapping. So use it to handle reserved ranges for record_file_blocks(). Signed-off-by: Qu Wenruo --- btrfs-convert.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 9 deletions(-) diff --git a/btrfs-convert.c b/btrfs-convert.c index 657fc1d..993ee80 100644 --- a/btrfs-convert.c +++ b/btrfs-convert.c @@ -464,7 +464,9 @@ static int csum_disk_extent(struct btrfs_trans_handle *trans, struct blk_iterate_data { struct btrfs_trans_handle *trans; struct btrfs_root *root; + struct btrfs_root *convert_root; struct btrfs_inode_item *inode; + u64 convert_ino; u64 objectid; u64 first_block; u64 disk_block; @@ -480,6 +482,8 @@ static void init_blk_iterate_data(struct blk_iterate_data *data, struct btrfs_inode_item *inode, u64 objectid, int checksum) { + struct btrfs_key key; + data->trans = trans; data->root = root; data->inode = inode; @@ -490,25 +494,100 @@ static void init_blk_iterate_data(struct blk_iterate_data *data, 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 since previously we just opened that subvolume */ + BUG_ON(!data->convert_root || IS_ERR(data->convert_root)); + data->convert_ino = BTRFS_FIRST_FREE_OBJECTID + 1; } static int record_file_blocks(struct blk_iterate_data *data, u64 file_block, u64 disk_block, u64 num_blocks) { - int ret; + 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 disk_bytenr = disk_block * root->sectorsize; + u64 old_disk_bytenr = disk_block * root->sectorsize; u64 num_bytes = num_blocks * root->sectorsize; - ret = btrfs_record_file_extent(data->trans, data->root, - data->objectid, data->inode, file_pos, - disk_bytenr, num_bytes); - - if (ret || !data->checksum || disk_bytenr == 0) - return ret; + u64 cur_off = old_disk_bytenr; - return csum_disk_extent(data->trans, data->root, disk_bytenr, + if (old_disk_bytenr == 0) + return btrfs_record_file_extent(data->trans, root, + data->objectid, data->inode, file_pos, 0, num_bytes); + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + /* + * Since the logical mapping of converted image is not all 1:1, + * especially for the reserved ranges, so we shouldn't use disk_bytenr + * directly, but search in convert_subvolume. + * Which acts like another logical <-> disk mapping layer. + */ + 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_disk_num_bytes(node, fi); + BUG_ON(cur_off - key.offset >= extent_num_bytes); + btrfs_release_path(path); + + real_disk_bytenr = cur_off - key.offset + extent_disk_bytenr; + 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; + /* + * Here we don't need to care about data checksum + * As all the ext* data is already calculated for csum, so no + * need to calculate it again + */ + } + + btrfs_free_path(path); + return ret; } static int block_iterate_proc(u64 disk_block, u64 file_block, @@ -1638,6 +1717,8 @@ static int create_ext2_image_v2(struct btrfs_root *root, &ino); if (ret < 0) goto out; + /* Shouldn't happen, and we need this const ino for later use */ + BUG_ON(ino != BTRFS_FIRST_FREE_OBJECTID + 1); ret = btrfs_new_inode(trans, root, ino, 0600 | S_IFREG); if (ret < 0) goto out;