diff mbox series

[RFC,28/31] btrfs: iomap_begin() for buffered read

Message ID 55e7d9c0cb329323d11f7782da1e69bb7ca9ccff.1623567940.git.rgoldwyn@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs buffered iomap support | expand

Commit Message

Goldwyn Rodrigues June 13, 2021, 1:39 p.m. UTC
From: Goldwyn Rodrigues <rgoldwyn@suse.com>

Lock the extents before performing a read.
Convert the offset/length to iomap by calling btrfs_em_to_iomap().
If reading from a hole, unlock the extent because iomap provides page
with zeros set.

Lock only the range on which iomap I/O can be performed. If iomap is
lesser than requested range, unlock extents beyond iomap
range.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
---
 fs/btrfs/inode.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)
diff mbox series

Patch

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index be0caf3a11f9..6b9b238837b8 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -8267,6 +8267,56 @@  static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 	return extent_fiemap(BTRFS_I(inode), fieinfo, start, len);
 }
 
+
+static int btrfs_read_iomap_begin(struct inode *inode, loff_t pos,
+		loff_t length, unsigned int flags, struct iomap *iomap,
+		struct iomap *srcmap)
+{
+	struct extent_state *cached_state = NULL;
+	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+	struct extent_map *em;
+	u64 start = round_down(pos, fs_info->sectorsize);
+	u64 end = round_up(pos + length, fs_info->sectorsize) - 1;
+
+	/* Lock the extent */
+	btrfs_lock_and_flush_ordered_range(BTRFS_I(inode),
+			start, end, &cached_state);
+
+	em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, end - start + 1);
+	if (IS_ERR(em))
+		return PTR_ERR(em);
+
+	btrfs_em_to_iomap(inode, em, iomap, start);
+	iomap->private = em;
+
+	if (iomap->type == IOMAP_HOLE) {
+		unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+				start, end, &cached_state);
+	} else if (end > iomap->offset + iomap->length) {
+		/* Unlock part beyond iomap */
+		unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+				iomap->offset + iomap->length,
+				end, &cached_state);
+	}
+
+	return 0;
+}
+
+static int btrfs_read_iomap_end(struct inode *inode, loff_t pos,
+		loff_t length, ssize_t written, unsigned int flags,
+		struct iomap *iomap)
+{
+	struct extent_map *em = iomap->private;
+
+	free_extent_map(em);
+	return 0;
+}
+
+const struct iomap_ops btrfs_buffered_read_iomap_ops = {
+	.iomap_begin = btrfs_read_iomap_begin,
+	.iomap_end = btrfs_read_iomap_end,
+};
+
 int btrfs_readpage(struct file *file, struct page *page)
 {
 	struct btrfs_inode *inode = BTRFS_I(page->mapping->host);