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

!9904 ext4: improve buffered write with more than one blocks_per_folio

Merge Pull Request from: @ci-robot 
 
PR sync from: Zhang Yi <yi.zhang@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/I3UAW4Z5SJGRJFSK2MIOMPEGQG5P7SPP/ 
In ext4_iomap_write_begin(), we speed up mapping check by checking the
folio dirty bit. If the folio is dirty, it means this folio has just
been written and must have a counterpart allocated block or delalloc
extent, so we don't need to map the folio again if we write to the same
place, this could speed up a lot for the case of repeated overwrite to
the same folio. However, we only check the entire folio has been dirty
or not, so it doesn't support if we have more than one blocks per folio
yet.

This series fix the handles of sub-folio properly in iomap, and extend
this improvement by checking partial blocks in one folio.

Zhang Yi (6):
  iomap: correct the range of a partial dirty clear
  iomap: support invalidating partial folios
  iomap: advance the ifs allocation if we have more than one blocks per
    folio
  iomap: correct the dirty length in page mkwrite
  iomap: add iomap_is_fully_dirty()
  ext4: improve sub-polio check in ext4_iomap_write_begin()


-- 
2.31.1
 
https://gitee.com/openeuler/kernel/issues/IACNS4 
 
Link:https://gitee.com/openeuler/kernel/pulls/9904

 

Reviewed-by: default avatarZhang Peng <zhangpeng362@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents b4a0c4ba a06ebc44
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3988,7 +3988,7 @@ static int ext4_iomap_write_begin(struct file *file,

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

	if (folio_test_dirty(folio) && (i_blocks_per_folio(inode, folio) == 1))
	if (iomap_is_fully_dirty(folio, offset_in_folio(folio, pos), len))
		goto out;

	do {
+55 −9
Original line number Diff line number Diff line
@@ -136,11 +136,14 @@ static void ifs_clear_range_dirty(struct folio *folio,
{
	struct inode *inode = folio->mapping->host;
	unsigned int blks_per_folio = i_blocks_per_folio(inode, folio);
	unsigned int first_blk = (off >> inode->i_blkbits);
	unsigned int last_blk = (off + len - 1) >> inode->i_blkbits;
	unsigned int nr_blks = last_blk - first_blk + 1;
	unsigned int first_blk = DIV_ROUND_UP(off, i_blocksize(inode));
	unsigned int last_blk = (off + len) >> inode->i_blkbits;
	unsigned int nr_blks = last_blk - first_blk;
	unsigned long flags;

	if (!nr_blks)
		return;

	spin_lock_irqsave(&ifs->state_lock, flags);
	bitmap_clear(ifs->state, first_blk + blks_per_folio, nr_blks);
	spin_unlock_irqrestore(&ifs->state_lock, flags);
@@ -177,6 +180,37 @@ static void iomap_set_range_dirty(struct folio *folio, size_t off, size_t len)
		ifs_set_range_dirty(folio, ifs, off, len);
}

/*
 * iomap_is_fully_dirty checks whether blocks within a folio are
 * dirty or not.
 *
 * Returns true if all blocks which correspond to the specified part
 * of the folio are dirty.
 */
bool iomap_is_fully_dirty(struct folio *folio, size_t from, size_t count)
{
	struct iomap_folio_state *ifs = folio->private;
	struct inode *inode = folio->mapping->host;
	unsigned first, last, i;

	if (!ifs)
		return folio_test_dirty(folio);

	/* Caller's range may extend past the end of this folio */
	count = min(folio_size(folio) - from, count);

	/* First and last blocks in range within folio */
	first = from >> inode->i_blkbits;
	last = (from + count - 1) >> inode->i_blkbits;

	for (i = first; i <= last; i++)
		if (!ifs_block_is_dirty(folio, ifs, i))
			return false;

	return true;
}
EXPORT_SYMBOL_GPL(iomap_is_fully_dirty);

static struct iomap_folio_state *ifs_alloc(struct inode *inode,
		struct folio *folio, unsigned int flags)
{
@@ -624,6 +658,8 @@ void iomap_invalidate_folio(struct folio *folio, size_t offset, size_t len)
		WARN_ON_ONCE(folio_test_writeback(folio));
		folio_cancel_dirty(folio);
		ifs_free(folio);
	} else {
		iomap_clear_range_dirty(folio, offset, len);
	}
}
EXPORT_SYMBOL_GPL(iomap_invalidate_folio);
@@ -677,6 +713,12 @@ int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
	size_t from = offset_in_folio(folio, pos), to = from + len;
	size_t poff, plen;

	if (nr_blocks > 1) {
		ifs = ifs_alloc(iter->inode, folio, iter->flags);
		if ((iter->flags & IOMAP_NOWAIT) && !ifs)
			return -EAGAIN;
	}

	/*
	 * If the write or zeroing completely overlaps the current folio, then
	 * entire folio will be dirtied so there is no need for
@@ -688,10 +730,6 @@ int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
	    pos + len >= folio_pos(folio) + folio_size(folio))
		return 0;

	ifs = ifs_alloc(iter->inode, folio, iter->flags);
	if ((iter->flags & IOMAP_NOWAIT) && !ifs && nr_blocks > 1)
		return -EAGAIN;

	if (folio_test_uptodate(folio))
		return 0;
	folio_clear_error(folio);
@@ -1481,7 +1519,10 @@ static loff_t iomap_folio_mkwrite_iter(struct iomap_iter *iter,
		block_commit_write(&folio->page, 0, length);
	} else {
		WARN_ON_ONCE(!folio_test_uptodate(folio));
		folio_mark_dirty(folio);

		ifs_alloc(iter->inode, folio, 0);
		iomap_set_range_dirty(folio, 0, length);
		filemap_dirty_folio(iter->inode->i_mapping, folio);
	}

	return length;
@@ -1920,7 +1961,12 @@ static int iomap_writepage_map(struct iomap_writepage_ctx *wpc,
	WARN_ON_ONCE(end_pos <= pos);

	if (i_blocks_per_folio(inode, folio) > 1) {
		if (!ifs) {
		/*
		 * This should not happen since we always allocate ifs in
		 * iomap_folio_mkwrite_iter() and there is more than one
		 * blocks per folio in __iomap_write_begin().
		 */
		if (WARN_ON_ONCE(!ifs)) {
			ifs = ifs_alloc(inode, folio, 0);
			iomap_set_range_dirty(folio, 0, end_pos - pos);
		}
+1 −0
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ int iomap_file_buffered_write_punch_delalloc(struct inode *inode,
int iomap_read_folio(struct folio *folio, const struct iomap_ops *ops);
void iomap_readahead(struct readahead_control *, const struct iomap_ops *ops);
bool iomap_is_partially_uptodate(struct folio *, size_t from, size_t count);
bool iomap_is_fully_dirty(struct folio *folio, size_t from, size_t count);
struct folio *iomap_get_folio(struct iomap_iter *iter, loff_t pos, size_t len);
bool iomap_release_folio(struct folio *folio, gfp_t gfp_flags);
void iomap_invalidate_folio(struct folio *folio, size_t offset, size_t len);