Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 364443cb authored by Jan Kara's avatar Jan Kara Committed by Theodore Ts'o
Browse files

ext4: convert DAX reads to iomap infrastructure



Implement basic iomap_begin function that handles reading and use it for
DAX reads.

Reviewed-by: default avatarRoss Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent a3caa24b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3266,6 +3266,8 @@ static inline bool ext4_aligned_io(struct inode *inode, loff_t off, loff_t len)
	return IS_ALIGNED(off, blksize) && IS_ALIGNED(len, blksize);
}

extern struct iomap_ops ext4_iomap_ops;

#endif	/* __KERNEL__ */

#define EFSBADCRC	EBADMSG		/* Bad CRC detected */
+37 −1
Original line number Diff line number Diff line
@@ -31,6 +31,42 @@
#include "xattr.h"
#include "acl.h"

#ifdef CONFIG_FS_DAX
static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	struct inode *inode = file_inode(iocb->ki_filp);
	ssize_t ret;

	inode_lock_shared(inode);
	/*
	 * Recheck under inode lock - at this point we are sure it cannot
	 * change anymore
	 */
	if (!IS_DAX(inode)) {
		inode_unlock_shared(inode);
		/* Fallback to buffered IO in case we cannot support DAX */
		return generic_file_read_iter(iocb, to);
	}
	ret = dax_iomap_rw(iocb, to, &ext4_iomap_ops);
	inode_unlock_shared(inode);

	file_accessed(iocb->ki_filp);
	return ret;
}
#endif

static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	if (!iov_iter_count(to))
		return 0; /* skip atime */

#ifdef CONFIG_FS_DAX
	if (IS_DAX(file_inode(iocb->ki_filp)))
		return ext4_dax_read_iter(iocb, to);
#endif
	return generic_file_read_iter(iocb, to);
}

/*
 * Called when an inode is released. Note that this is different
 * from ext4_file_open: open gets called at every open, but release
@@ -690,7 +726,7 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence)

const struct file_operations ext4_file_operations = {
	.llseek		= ext4_llseek,
	.read_iter	= generic_file_read_iter,
	.read_iter	= ext4_file_read_iter,
	.write_iter	= ext4_file_write_iter,
	.unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
+54 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/iomap.h>

#include "ext4_jbd2.h"
#include "xattr.h"
@@ -3318,6 +3319,59 @@ int ext4_dax_get_block(struct inode *inode, sector_t iblock,
	clear_buffer_new(bh_result);
	return 0;
}

static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
			    unsigned flags, struct iomap *iomap)
{
	unsigned int blkbits = inode->i_blkbits;
	unsigned long first_block = offset >> blkbits;
	unsigned long last_block = (offset + length - 1) >> blkbits;
	struct ext4_map_blocks map;
	int ret;

	if (flags & IOMAP_WRITE)
		return -EIO;

	if (WARN_ON_ONCE(ext4_has_inline_data(inode)))
		return -ERANGE;

	map.m_lblk = first_block;
	map.m_len = last_block - first_block + 1;

	ret = ext4_map_blocks(NULL, inode, &map, 0);
	if (ret < 0)
		return ret;

	iomap->flags = 0;
	iomap->bdev = inode->i_sb->s_bdev;
	iomap->offset = first_block << blkbits;

	if (ret == 0) {
		iomap->type = IOMAP_HOLE;
		iomap->blkno = IOMAP_NULL_BLOCK;
		iomap->length = (u64)map.m_len << blkbits;
	} else {
		if (map.m_flags & EXT4_MAP_MAPPED) {
			iomap->type = IOMAP_MAPPED;
		} else if (map.m_flags & EXT4_MAP_UNWRITTEN) {
			iomap->type = IOMAP_UNWRITTEN;
		} else {
			WARN_ON_ONCE(1);
			return -EIO;
		}
		iomap->blkno = (sector_t)map.m_pblk << (blkbits - 9);
		iomap->length = (u64)map.m_len << blkbits;
	}

	if (map.m_flags & EXT4_MAP_NEW)
		iomap->flags |= IOMAP_F_NEW;
	return 0;
}

struct iomap_ops ext4_iomap_ops = {
	.iomap_begin		= ext4_iomap_begin,
};

#else
/* Just define empty function, it will never get called. */
int ext4_dax_get_block(struct inode *inode, sector_t iblock,