Unverified Commit 4da472bb authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!7527 ext4 iomap performance optimize

Merge Pull Request from: @ci-robot 
 
PR sync from: Yang Erkun <yangerkun@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/MJG2WBSZZBC5XBTLEVUSWIXZLVE2Z5QI/ 
*** BLURB HERE ***

Yang Erkun (2):
  iomap: export __iomap_write_{begin|end}
  ext4: fallback to generic_perform_write once iov_iter_count <=
    PAGE_SIZE


-- 
2.39.2
 
https://gitee.com/openeuler/kernel/issues/I9DN5Z 
 
Link:https://gitee.com/openeuler/kernel/pulls/7527

 

Reviewed-by: default avatarzhangyi (F) <yi.zhang@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 7db2768c f50c7b86
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -314,7 +314,8 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb,
	if (ret <= 0)
		goto out;

	if (ext4_test_inode_state(inode, EXT4_STATE_BUFFERED_IOMAP))
	if (ext4_test_inode_state(inode, EXT4_STATE_BUFFERED_IOMAP) &&
	    iov_iter_count(from) > PAGE_SIZE)
		ret = ext4_iomap_buffered_write(iocb, from);
	else
		ret = generic_perform_write(iocb, from);
+124 −0
Original line number Diff line number Diff line
@@ -3955,6 +3955,128 @@ static int ext4_iomap_writepages(struct address_space *mapping,
	return ret;
}

static int ext4_iomap_write_begin(struct file *file,
				  struct address_space *mapping, loff_t pos,
				  unsigned len, struct page **pagep,
				  void **fsdata)
{
	struct inode *inode = mapping->host;
	struct iomap_iter iter = {
		.inode	= inode,
		.flags	= IOMAP_WRITE,
	};
	int ret = 0, retries = 0;
	struct folio *folio;
	bool delalloc;

	if (unlikely(ext4_forced_shutdown(inode->i_sb)))
		return -EIO;

	trace_ext4_iomap_write_begin(inode, pos, len);

	delalloc = test_opt(inode->i_sb, DELALLOC) &&
		   !ext4_nonda_switch(inode->i_sb);
	*fsdata = delalloc ? (void *)0 : (void *)FALL_BACK_TO_NONDELALLOC;

retry:
	iter.pos = pos;
	iter.len = len;

	folio = iomap_get_folio(&iter, pos, len);
	if (IS_ERR(folio))
		return PTR_ERR(folio);

	WARN_ON_ONCE(pos + len > folio_pos(folio) + folio_size(folio));

	if (folio_test_dirty(folio) && (i_blocks_per_folio(inode, folio) == 1))
		goto out;

	do {
		int length;

		ret = __ext4_iomap_buffered_io_begin(inode, iter.pos, iter.len,
				iter.flags, &iter.iomap, NULL, delalloc);
		if (ret)
			goto out;

		WARN_ON_ONCE(iter.iomap.offset > iter.pos);
		WARN_ON_ONCE(iter.iomap.length == 0);
		WARN_ON_ONCE(iter.iomap.offset + iter.iomap.length <= iter.pos);

		length = iomap_length(&iter);
		ret = __iomap_write_begin(&iter, iter.pos, length, folio);
		if (ret)
			goto out;

		iter.pos += length;
		iter.len -= length;
	} while (iter.len);

out:
	if (ret < 0) {
		folio_unlock(folio);
		folio_put(folio);

		/*
		 * __ext4_iomap_buffered_io_begin() may have instantiated
		 * a few blocks outside i_size. Trim these off again. Don't
		 * need i_size_read because we hold inode lock.
		 */
		if (pos + len > inode->i_size)
			ext4_truncate_failed_write(inode);

		if (ret == -ENOSPC &&
		    ext4_should_retry_alloc(inode->i_sb, &retries))
			goto retry;
	}

	*pagep = folio_file_page(folio, pos >> PAGE_SHIFT);
	return ret;
}

static int ext4_iomap_write_end(struct file *file,
				struct address_space *mapping,
				loff_t pos, unsigned len, unsigned copied,
				struct page *page, void *fsdata)
{
	struct inode *inode = mapping->host;
	int write_mode = (int)(unsigned long)fsdata;
	struct folio *folio = page_folio(page);
	loff_t old_size = inode->i_size;
	size_t written;

	trace_ext4_iomap_write_end(inode, pos, len, copied);

	written = __iomap_write_end(inode, pos, len, copied, folio) ?
		  copied : 0;

	/*
	 * Update the in-memory inode size after copying the data into
	 * the page cache. It's important to update i_size while still
	 * holding folio lock, because folio writeout could otherwise
	 * come in and zero beyond i_size.
	 */
	if (pos + written > old_size)
		i_size_write(inode, pos + written);

	folio_unlock(folio);
	folio_put(folio);

	if (old_size < pos)
		pagecache_isize_extended(inode, old_size, pos);

	/*
	 * For delalloc, if we have pre-allocated more blocks and copied
	 * less, we will have delalloc extents allocated outside i_size,
	 * drop pre-allocated blocks that were not used, prevent the
	 * write back path from allocating blocks for them.
	 */
	if (unlikely(!written) && write_mode != FALL_BACK_TO_NONDELALLOC)
		ext4_truncate_failed_write(inode);

	return written;
}

/*
 * For data=journal mode, folio should be marked dirty only when it was
 * writeably mapped. When that happens, it was already attached to the
@@ -4048,6 +4170,8 @@ static const struct address_space_operations ext4_iomap_aops = {
	.read_folio		= ext4_iomap_read_folio,
	.readahead		= ext4_iomap_readahead,
	.writepages		= ext4_iomap_writepages,
	.write_begin		= ext4_iomap_write_begin,
	.write_end		= ext4_iomap_write_end,
	.dirty_folio		= iomap_dirty_folio,
	.bmap			= ext4_bmap,
	.invalidate_folio	= iomap_invalidate_folio,
+4 −2
Original line number Diff line number Diff line
@@ -665,7 +665,7 @@ static int iomap_read_folio_sync(loff_t block_start, struct folio *folio,
	return submit_bio_wait(&bio);
}

static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
		size_t len, struct folio *folio)
{
	const struct iomap *srcmap = iomap_iter_srcmap(iter);
@@ -727,6 +727,7 @@ static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,

	return 0;
}
EXPORT_SYMBOL_GPL(__iomap_write_begin);

static struct folio *__iomap_get_folio(struct iomap_iter *iter, loff_t pos,
		size_t len)
@@ -825,7 +826,7 @@ static int iomap_write_begin(struct iomap_iter *iter, loff_t pos,
	return status;
}

static bool __iomap_write_end(struct inode *inode, loff_t pos, size_t len,
bool __iomap_write_end(struct inode *inode, loff_t pos, size_t len,
		size_t copied, struct folio *folio)
{
	flush_dcache_folio(folio);
@@ -848,6 +849,7 @@ static bool __iomap_write_end(struct inode *inode, loff_t pos, size_t len,
	filemap_dirty_folio(inode->i_mapping, folio);
	return true;
}
EXPORT_SYMBOL_GPL(__iomap_write_end);

static void iomap_write_end_inline(const struct iomap_iter *iter,
		struct folio *folio, loff_t pos, size_t copied)
+4 −0
Original line number Diff line number Diff line
@@ -258,6 +258,10 @@ static inline const struct iomap *iomap_iter_srcmap(const struct iomap_iter *i)

ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
		const struct iomap_ops *ops);
int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
		size_t len, struct folio *folio);
bool __iomap_write_end(struct inode *inode, loff_t pos, size_t len,
		size_t copied, struct folio *folio);
int iomap_file_buffered_write_punch_delalloc(struct inode *inode,
		struct iomap *iomap, loff_t pos, loff_t length, ssize_t written,
		int (*punch)(struct inode *inode, loff_t pos, loff_t length));
+15 −0
Original line number Diff line number Diff line
@@ -389,6 +389,13 @@ DEFINE_EVENT(ext4__write_begin, ext4_da_write_begin,
	TP_ARGS(inode, pos, len)
);

DEFINE_EVENT(ext4__write_begin, ext4_iomap_write_begin,

	TP_PROTO(struct inode *inode, loff_t pos, unsigned int len),

	TP_ARGS(inode, pos, len)
);

DECLARE_EVENT_CLASS(ext4__write_end,
	TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
			unsigned int copied),
@@ -441,6 +448,14 @@ DEFINE_EVENT(ext4__write_end, ext4_da_write_end,
	TP_ARGS(inode, pos, len, copied)
);

DEFINE_EVENT(ext4__write_end, ext4_iomap_write_end,

	TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
		 unsigned int copied),

	TP_ARGS(inode, pos, len, copied)
);

TRACE_EVENT(ext4_writepages,
	TP_PROTO(struct inode *inode, struct writeback_control *wbc),