Commit 16705e52 authored by Zhang Yi's avatar Zhang Yi Committed by Theodore Ts'o
Browse files

ext4: make regular file's buffered write path support large folios



The current buffered write path in ext4 can only allocate and handle
folios of PAGE_SIZE size. To support larger folios, modify
ext4_da_write_begin() and ext4_write_begin() to allocate higher-order
folios, and trim the write length if it exceeds the folio size.
Additionally, in ext4_da_do_write_end(), use offset_in_folio() instead
of PAGE_SIZE.

Signed-off-by: default avatarZhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20250512063319.3539411-3-yi.zhang@huaweicloud.com


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent fdbd0df9
Loading
Loading
Loading
Loading
+21 −10
Original line number Diff line number Diff line
@@ -1066,7 +1066,7 @@ int ext4_block_write_begin(handle_t *handle, struct folio *folio,
			   loff_t pos, unsigned len,
			   get_block_t *get_block)
{
	unsigned from = pos & (PAGE_SIZE - 1);
	unsigned int from = offset_in_folio(folio, pos);
	unsigned to = from + len;
	struct inode *inode = folio->mapping->host;
	unsigned block_start, block_end;
@@ -1080,8 +1080,7 @@ int ext4_block_write_begin(handle_t *handle, struct folio *folio,
	bool should_journal_data = ext4_should_journal_data(inode);

	BUG_ON(!folio_test_locked(folio));
	BUG_ON(from > PAGE_SIZE);
	BUG_ON(to > PAGE_SIZE);
	BUG_ON(to > folio_size(folio));
	BUG_ON(from > to);

	head = folio_buffers(folio);
@@ -1191,6 +1190,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
	struct folio *folio;
	pgoff_t index;
	unsigned from, to;
	fgf_t fgp = FGP_WRITEBEGIN;

	ret = ext4_emergency_state(inode->i_sb);
	if (unlikely(ret))
@@ -1203,8 +1203,6 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
	 */
	needed_blocks = ext4_writepage_trans_blocks(inode) + 1;
	index = pos >> PAGE_SHIFT;
	from = pos & (PAGE_SIZE - 1);
	to = from + len;

	if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
		ret = ext4_try_to_write_inline_data(mapping, inode, pos, len,
@@ -1223,10 +1221,18 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
	 * the folio (if needed) without using GFP_NOFS.
	 */
retry_grab:
	folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
	fgp |= fgf_set_order(len);
	folio = __filemap_get_folio(mapping, index, fgp,
				    mapping_gfp_mask(mapping));
	if (IS_ERR(folio))
		return PTR_ERR(folio);

	if (pos + len > folio_pos(folio) + folio_size(folio))
		len = folio_pos(folio) + folio_size(folio) - pos;

	from = offset_in_folio(folio, pos);
	to = from + len;

	/*
	 * The same as page allocation, we prealloc buffer heads before
	 * starting the handle.
@@ -2965,6 +2971,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
	struct folio *folio;
	pgoff_t index;
	struct inode *inode = mapping->host;
	fgf_t fgp = FGP_WRITEBEGIN;

	ret = ext4_emergency_state(inode->i_sb);
	if (unlikely(ret))
@@ -2990,11 +2997,15 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
	}

retry:
	folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
	fgp |= fgf_set_order(len);
	folio = __filemap_get_folio(mapping, index, fgp,
				    mapping_gfp_mask(mapping));
	if (IS_ERR(folio))
		return PTR_ERR(folio);

	if (pos + len > folio_pos(folio) + folio_size(folio))
		len = folio_pos(folio) + folio_size(folio) - pos;

	ret = ext4_block_write_begin(NULL, folio, pos, len,
				     ext4_da_get_block_prep);
	if (ret < 0) {
@@ -3083,7 +3094,7 @@ static int ext4_da_do_write_end(struct address_space *mapping,
		unsigned long end;

		i_size_write(inode, new_i_size);
		end = (new_i_size - 1) & (PAGE_SIZE - 1);
		end = offset_in_folio(folio, new_i_size - 1);
		if (copied && ext4_da_should_update_i_disksize(folio, end)) {
			ext4_update_i_disksize(inode, new_i_size);
			disksize_changed = true;