linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Qu Wenruo <wqu@suse.com>
To: linux-btrfs@vger.kernel.org, u-boot@lists.denx.de
Cc: marek.behun@nic.cz
Subject: [PATCH U-BOOT v2 25/30] fs: btrfs: Implement btrfs_file_read()
Date: Mon, 25 May 2020 14:32:52 +0800	[thread overview]
Message-ID: <20200525063257.46757-26-wqu@suse.com> (raw)
In-Reply-To: <20200525063257.46757-1-wqu@suse.com>

This version of btrfs_file_read() will have the following new features:
- Try all mirrors
- More hanlding on unaligned size
- Better compressed extent handling
  The old implementation doesn't handle compressed extent with offset
  properly.
  As we need to read out the whole compressed extent, then decompress
  the whole extent, then only copy the referred part.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/btrfs.c |  48 +++++++++-------
 fs/btrfs/btrfs.h |   2 +
 fs/btrfs/inode.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+), 20 deletions(-)

diff --git a/fs/btrfs/btrfs.c b/fs/btrfs/btrfs.c
index 7eb01c4ff9b5..ffd96427ccdc 100644
--- a/fs/btrfs/btrfs.c
+++ b/fs/btrfs/btrfs.c
@@ -253,37 +253,45 @@ out:
 int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
 	       loff_t *actread)
 {
-	struct __btrfs_root root = btrfs_info.fs_root;
-	struct btrfs_inode_item inode;
-	u64 inr, rd;
+	struct btrfs_fs_info *fs_info = current_fs_info;
+	struct btrfs_root *root;
+	loff_t real_size;
+	u64 ino;
 	u8 type;
+	int ret;
 
-	inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
-				40);
-
-	if (inr == -1ULL) {
-		printf("Cannot lookup file %s\n", file);
-		return -1;
+	ASSERT(fs_info);
+	ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
+				file, &root, &ino, &type, 40);
+	if (ret < 0) {
+		error("Cannot lookup file %s", file);
+		return ret;
 	}
 
 	if (type != BTRFS_FT_REG_FILE) {
-		printf("Not a regular file: %s\n", file);
-		return -1;
+		error("Not a regular file: %s", file);
+		return -EINVAL;
 	}
 
-	if (!len)
-		len = inode.size;
+	if (!len) {
+		ret = btrfs_size(file, &real_size);
+		if (ret < 0) {
+			error("Failed to get inode size: %s", file);
+			return ret;
+		}
+		len = real_size;
+	}
 
-	if (len > inode.size - offset)
-		len = inode.size - offset;
+	if (len > real_size - offset)
+		len = real_size - offset;
 
-	rd = __btrfs_file_read(&root, inr, offset, len, buf);
-	if (rd == -1ULL) {
-		printf("An error occured while reading file %s\n", file);
-		return -1;
+	ret = btrfs_file_read(root, ino, offset, len, buf);
+	if (ret < 0) {
+		error("An error occured while reading file %s", file);
+		return ret;
 	}
 
-	*actread = rd;
+	*actread = len;
 	return 0;
 }
 
diff --git a/fs/btrfs/btrfs.h b/fs/btrfs/btrfs.h
index 32ea2fc53aa5..268ca077d96a 100644
--- a/fs/btrfs/btrfs.h
+++ b/fs/btrfs/btrfs.h
@@ -59,6 +59,8 @@ int btrfs_readlink(struct btrfs_root *root, u64 ino, char *target);
 u64 __btrfs_lookup_path(struct __btrfs_root *, u64, const char *, u8 *,
 		       struct btrfs_inode_item *, int);
 u64 __btrfs_file_read(const struct __btrfs_root *, u64, u64, u64, char *);
+int btrfs_file_read(struct btrfs_root *root, u64 ino, u64 file_offset, u64 len,
+		    char *dest);
 
 /* subvolume.c */
 u64 btrfs_get_default_subvol_objectid(void);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 9a1b1d265bdd..f671e86c1f91 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -920,3 +920,149 @@ check_next:
 	*next_offset = key.offset;
 	return 1;
 }
+
+static int read_and_truncate_page(struct btrfs_path *path,
+				  struct btrfs_file_extent_item *fi,
+				  int start, int len, char *dest)
+{
+	struct extent_buffer *leaf = path->nodes[0];
+	struct btrfs_fs_info *fs_info = leaf->fs_info;
+	u64 aligned_start = round_down(start, fs_info->sectorsize);
+	u8 extent_type;
+	char *buf;
+	int page_off = start - aligned_start;
+	int page_len = fs_info->sectorsize - page_off;
+	int ret;
+
+	ASSERT(start + len <= aligned_start + fs_info->sectorsize);
+	buf = malloc_cache_aligned(fs_info->sectorsize);
+	if (!buf)
+		return -ENOMEM;
+
+	extent_type = btrfs_file_extent_type(leaf, fi);
+	if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
+		ret = btrfs_read_extent_inline(path, fi, buf);
+		memcpy(dest, buf + page_off, min(page_len, ret));
+		free(buf);
+		return len;
+	}
+
+	ret = btrfs_read_extent_reg(path, fi,
+			round_down(start, fs_info->sectorsize),
+			fs_info->sectorsize, buf);
+	if (ret < 0) {
+		free(buf);
+		return ret;
+	}
+	memcpy(dest, buf + page_off, page_len);
+	free(buf);
+	return len;
+}
+
+int btrfs_file_read(struct btrfs_root *root, u64 ino, u64 file_offset, u64 len,
+		    char *dest)
+{
+	struct btrfs_fs_info *fs_info = root->fs_info;
+	struct btrfs_file_extent_item *fi;
+	struct btrfs_path path;
+	struct btrfs_key key;
+	u64 aligned_start = round_down(file_offset, fs_info->sectorsize);
+	u64 aligned_end = round_down(file_offset + len, fs_info->sectorsize);
+	u64 next_offset;
+	u64 cur = aligned_start;
+	int ret = 0;
+
+	btrfs_init_path(&path);
+
+	/* Set the whole dest all zero, so we won't need to bother holes */
+	memset(dest, 0, len);
+
+	/* Read out the leading unaligned part */
+	if (aligned_start != file_offset) {
+		ret = lookup_data_extent(root, &path, ino, aligned_start,
+					 &next_offset); 
+		if (ret < 0)
+			goto out;
+		if (ret == 0) {
+			/* Read the unaligned part out*/
+			fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
+					struct btrfs_file_extent_item);
+			ret = read_and_truncate_page(&path, fi, file_offset,
+					round_up(file_offset, fs_info->sectorsize) -
+					file_offset, dest);
+			if (ret < 0)
+				goto out;
+			cur += fs_info->sectorsize;
+		} else {
+			/* The whole file is a hole */
+			if (!next_offset) {
+				memset(dest, 0, len);
+				return len;
+			}
+			cur = next_offset;
+		}
+	}
+
+	/* Read the aligned part */
+	while (cur < aligned_end) {
+		u64 extent_num_bytes;
+		u8 type;
+
+		btrfs_release_path(&path);
+		ret = lookup_data_extent(root, &path, ino, cur, &next_offset);
+		if (ret < 0)
+			goto out;
+		if (ret > 0) {
+			/* No next, direct exit */
+			if (!next_offset) {
+				ret = 0;
+				goto out;
+			}
+		}
+		fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
+				    struct btrfs_file_extent_item);
+		btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+		type = btrfs_file_extent_type(path.nodes[0], fi);
+		if (type == BTRFS_FILE_EXTENT_INLINE) {
+			ret = btrfs_read_extent_inline(&path, fi, dest);
+			goto out;
+		}
+		/* Skip holes, as we have zeroed the dest */
+		if (type == BTRFS_FILE_EXTENT_PREALLOC ||
+		    btrfs_file_extent_disk_bytenr(path.nodes[0], fi) == 0) {
+			cur = key.offset + btrfs_file_extent_num_bytes(
+					path.nodes[0], fi);
+			continue;
+		}
+
+		/* Read the remaining part of the extent */
+		extent_num_bytes = btrfs_file_extent_num_bytes(path.nodes[0],
+							       fi);
+		ret = btrfs_read_extent_reg(&path, fi, cur,
+				min(extent_num_bytes, aligned_end - cur),
+				dest + cur - file_offset);
+		if (ret < 0)
+			goto out;
+		cur += min(extent_num_bytes, aligned_end - cur);
+	}
+
+	/* Read the tailing unaligned part*/
+	if (file_offset + len != aligned_end) {
+		btrfs_release_path(&path);
+		ret = lookup_data_extent(root, &path, ino, aligned_end,
+					 &next_offset);
+		/* <0 is error, >0 means no extent */
+		if (ret)
+			goto out;
+		fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
+				    struct btrfs_file_extent_item);
+		ret = read_and_truncate_page(&path, fi, aligned_end,
+				file_offset + len - aligned_end,
+				dest + aligned_end - file_offset);
+	}
+out:
+	btrfs_release_path(&path);
+	if (ret < 0)
+		return ret;
+	return len;
+}
-- 
2.26.2


  parent reply	other threads:[~2020-05-25  6:34 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-25  6:32 [PATCH U-BOOT v2 00/30] fs: btrfs: Re-implement btrfs support using the more widely used extent buffer base code Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 01/30] fs: btrfs: Sync btrfs_btree.h from kernel Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 02/30] fs: btrfs: Add More checksum algorithm support to btrfs Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 03/30] fs: btrfs: Cross-port btrfs_read_dev_super() from btrfs-progs Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 04/30] fs: btrfs: Cross-port rbtree-utils " Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 05/30] fs: btrfs: Cross-port extent-cache.[ch] " Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 06/30] fs: btrfs: Cross-port extent-io.[ch] " Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 07/30] fs: btrfs: Cross port structure accessor into ctree.h Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 08/30] fs: btrfs: Cross port volumes.[ch] from btrfs-progs Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 09/30] fs: btrfs: Crossport read_tree_block() " Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 10/30] fs: btrfs: Rename struct btrfs_path to struct __btrfs_path Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 11/30] fs: btrfs: Rename btrfs_root to __btrfs_root Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 12/30] fs: btrfs: Cross port struct btrfs_root to ctree.h Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 13/30] fs: btrfs: Crossport btrfs_search_slot() from btrfs-progs Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 14/30] fs: btrfs: Crossport btrfs_read_sys_array() and btrfs_read_chunk_tree() Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 15/30] fs: btrfs: Crossport open_ctree_fs_info() Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 16/30] fs: btrfs: Rename path resolve related functions to avoid name conflicts Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 17/30] fs: btrfs: Use btrfs_readlink() to implement __btrfs_readlink() Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 18/30] fs: btrfs: inode: Allow next_length() to return value > BTRFS_NAME_LEN Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 19/30] fs: btrfs: Implement btrfs_lookup_path() Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 20/30] fs: btrfs: Use btrfs_iter_dir() to replace btrfs_readdir() Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 21/30] fs: btrfs: Use btrfs_lookup_path() to implement btrfs_exists() and btrfs_size() Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 22/30] fs: btrfs: Rename btrfs_file_read() and its callees to avoid name conflicts Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 23/30] fs: btrfs: Introduce btrfs_read_extent_inline() and btrfs_read_extent_reg() Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 24/30] fs: btrfs: Introduce lookup_data_extent() for later use Qu Wenruo
2020-05-25  6:32 ` Qu Wenruo [this message]
2020-05-25  6:32 ` [PATCH U-BOOT v2 26/30] fs: btrfs: Introduce function to reolve path in one subvolume Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 27/30] fs: btrfs: Introduce function to resolve the path of " Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 28/30] fs: btrfs: Imeplement btrfs_list_subvols() using new infrastructure Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 29/30] fs: btrfs: Cleanup the old implementation Qu Wenruo
2020-05-25  6:32 ` [PATCH U-BOOT v2 30/30] MAINTAINERS: Add btrfs mail list Qu Wenruo
2020-06-23  0:50 ` [PATCH U-BOOT v2 00/30] fs: btrfs: Re-implement btrfs support using the more widely used extent buffer base code Qu Wenruo
2020-06-23 15:05   ` Marek Behún

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200525063257.46757-26-wqu@suse.com \
    --to=wqu@suse.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=marek.behun@nic.cz \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).