From patchwork Fri Feb 24 05:52:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 9589419 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 05CEB6057F for ; Fri, 24 Feb 2017 05:55:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EBBBE287A2 for ; Fri, 24 Feb 2017 05:55:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DB8E7287A7; Fri, 24 Feb 2017 05:55:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 646CB287A2 for ; Fri, 24 Feb 2017 05:55:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751190AbdBXFyf (ORCPT ); Fri, 24 Feb 2017 00:54:35 -0500 Received: from cn.fujitsu.com ([59.151.112.132]:31160 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1750937AbdBXFyc (ORCPT ); Fri, 24 Feb 2017 00:54:32 -0500 X-IronPort-AV: E=Sophos;i="5.22,518,1449504000"; d="scan'208";a="15915854" Received: from unknown (HELO cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 24 Feb 2017 13:52:51 +0800 Received: from G08CNEXCHPEKD01.g08.fujitsu.local (unknown [10.167.33.80]) by cn.fujitsu.com (Postfix) with ESMTP id 526A247C4EAF; Fri, 24 Feb 2017 13:52:51 +0800 (CST) Received: from localhost.localdomain (10.167.226.34) by G08CNEXCHPEKD01.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.319.2; Fri, 24 Feb 2017 13:52:50 +0800 From: Qu Wenruo To: , Subject: [PATCH v2 6/9] btrfs-progs: file: Introduce function to read out file content Date: Fri, 24 Feb 2017 13:52:29 +0800 Message-ID: <20170224055232.4140-7-quwenruo@cn.fujitsu.com> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170224055232.4140-1-quwenruo@cn.fujitsu.com> References: <20170224055232.4140-1-quwenruo@cn.fujitsu.com> MIME-Version: 1.0 X-Originating-IP: [10.167.226.34] X-yoursite-MailScanner-ID: 526A247C4EAF.AFBAB X-yoursite-MailScanner: Found to be clean X-yoursite-MailScanner-From: quwenruo@cn.fujitsu.com Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Introduce a new function, btrfs_read_file(), to read out data of a file inode. This function will iterate through EXTENT_DATA items and handle inline/prealloc/hole file extents. Compression is not supported yet. Signed-off-by: Qu Wenruo --- ctree.h | 2 + file.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) diff --git a/ctree.h b/ctree.h index 401257f4..e8dfa0e9 100644 --- a/ctree.h +++ b/ctree.h @@ -2799,4 +2799,6 @@ int btrfs_get_extent(struct btrfs_trans_handle *trans, int btrfs_punch_hole(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 offset, u64 len); +int btrfs_read_file(struct btrfs_root *root, u64 ino, u64 start, u64 len, + char *dest); #endif diff --git a/file.c b/file.c index dd0b04b8..9b812010 100644 --- a/file.c +++ b/file.c @@ -18,6 +18,8 @@ #include #include "ctree.h" +#include "utils.h" +#include "disk-io.h" #include "transaction.h" #include "kerncompat.h" @@ -160,3 +162,169 @@ out: btrfs_free_path(path); return ret; } + +/* + * Read out content of one inode. + * + * @root: fs/subvolume root containing the inode + * @ino: inode number + * @start: offset inside the file, aligned to sectorsize + * @len: length to read, aligned to sectorisize + * @dest: where data will be stored + * + * NOTE: + * 1) compression data is not supported yet. + * 2) @start and @len must be aligned to sectorsize + * 3) data read out is also aligned to sectorsize, not truncated to inode size + * + * Return < 0 for fatal error during read. + * Otherwise return the number of suceeful read out data. + */ +int btrfs_read_file_data(struct btrfs_root *root, u64 ino, u64 start, int len, + char *dest) +{ + struct btrfs_key key; + struct btrfs_path path; + struct extent_buffer *leaf; + struct btrfs_inode_item *ii; + u64 isize; + int no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES); + int slot; + int read = 0; + int ret; + + if (!IS_ALIGNED(start, root->sectorsize) || + !IS_ALIGNED(len, root->sectorsize)) { + warning("@start and @len must be aligned to %u for function %s", + root->sectorsize, __func__); + return -EINVAL; + } + + btrfs_init_path(&path); + key.objectid = ino; + key.offset = start; + key.type = BTRFS_EXTENT_DATA_KEY; + + ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); + if (ret < 0) + goto out; + + if (ret > 0) { + ret = btrfs_previous_item(root, &path, ino, BTRFS_EXTENT_DATA_KEY); + if (ret > 0) { + ret = -ENOENT; + goto out; + } + } + + /* + * Reset @dest to all 0, so we don't need to care about holes in + * no_hole mode, but focus on reading non-hole part. + */ + memset(dest, 0, len); + while (1) { + struct btrfs_file_extent_item *fi; + u64 extent_start; + u64 extent_len; + u64 read_start; + u64 read_len; + u64 read_len_ret; + u64 disk_bytenr; + + leaf = path.nodes[0]; + slot = path.slots[0]; + + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.objectid > ino) + break; + if (key.type != BTRFS_EXTENT_DATA_KEY || key.objectid != ino) + goto next; + + extent_start = key.offset; + if (extent_start >= start + len) + break; + + fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + if (btrfs_file_extent_compression(leaf, fi) != + BTRFS_COMPRESS_NONE) { + ret = -ENOTTY; + break; + } + + /* Inline extent, one inode should only one inline extent */ + if (btrfs_file_extent_type(leaf, fi) == + BTRFS_FILE_EXTENT_INLINE) { + extent_len = btrfs_file_extent_inline_len(leaf, slot, + fi); + if (extent_start + extent_len <= start) + goto next; + read_extent_buffer(leaf, dest, + btrfs_file_extent_inline_start(fi), extent_len); + read += round_up(extent_len, root->sectorsize); + break; + } + + extent_len = btrfs_file_extent_num_bytes(leaf, fi); + if (extent_start + extent_len <= start) + goto next; + + read_start = max(start, extent_start); + read_len = min(start + len, extent_start + extent_len) - + read_start; + + /* We have already zeroed @dest, nothing to do */ + if (btrfs_file_extent_type(leaf, fi) == + BTRFS_FILE_EXTENT_PREALLOC || + btrfs_file_extent_disk_num_bytes(leaf, fi) == 0) { + read += read_len; + goto next; + } + + disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi) + + btrfs_file_extent_offset(leaf, fi); + read_len_ret = read_len; + ret = read_extent_data(root, dest + read_start - start, disk_bytenr, + &read_len_ret, 0); + if (ret < 0) + break; + /* Short read, something went wrong */ + if (read_len_ret != read_len) + return -EIO; + read += read_len; +next: + ret = btrfs_next_item(root, &path); + if (ret > 0) { + ret = 0; + break; + } + } + + /* + * Special trick for no_holes, since for no_holes we don't have good + * method to account skipped and tailling holes, we used + * min(inode size, len) as return value + */ + if (no_holes) { + btrfs_release_path(&path); + key.objectid = ino; + key.offset = 0; + key.type = BTRFS_INODE_ITEM_KEY; + ret = btrfs_lookup_inode(NULL, root, &path, &key, 0); + if (ret < 0) + goto out; + if (ret > 0) { + ret = -ENOENT; + goto out; + } + ii = btrfs_item_ptr(path.nodes[0], path.slots[0], + struct btrfs_inode_item); + isize = round_up(btrfs_inode_size(path.nodes[0], ii), + root->sectorsize); + read = min_t(u64, isize - start, len); + } +out: + btrfs_release_path(&path); + if (!ret) + ret = read; + return ret; +}