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

ext4: refactor ext4_insert_range()



Simplify ext4_insert_range() and align its code style with that of
ext4_collapse_range(). Refactor it by: a) renaming variables, b)
removing redundant input parameter checks and moving the remaining
checks under i_rwsem in preparation for future refactoring, and c)
renaming the three stale error tags.

Signed-off-by: default avatarZhang Yi <yi.zhang@huawei.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Reviewed-by: default avatarOjaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20241220011637.1157197-8-yi.zhang@huaweicloud.com


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 162e3c5a
Loading
Loading
Loading
Loading
+48 −53
Original line number Diff line number Diff line
@@ -5425,45 +5425,37 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
	handle_t *handle;
	struct ext4_ext_path *path;
	struct ext4_extent *extent;
	ext4_lblk_t offset_lblk, len_lblk, ee_start_lblk = 0;
	ext4_lblk_t start_lblk, len_lblk, ee_start_lblk = 0;
	unsigned int credits, ee_len;
	int ret = 0, depth, split_flag = 0;
	loff_t ioffset;

	/*
	 * We need to test this early because xfstests assumes that an
	 * insert range of (0, 1) will return EOPNOTSUPP if the file
	 * system does not support insert range.
	 */
	if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
		return -EOPNOTSUPP;

	/* Insert range works only on fs cluster size aligned regions. */
	if (!IS_ALIGNED(offset | len, EXT4_CLUSTER_SIZE(sb)))
		return -EINVAL;
	int ret, depth, split_flag = 0;
	loff_t start;

	trace_ext4_insert_range(inode, offset, len);

	offset_lblk = offset >> EXT4_BLOCK_SIZE_BITS(sb);
	len_lblk = len >> EXT4_BLOCK_SIZE_BITS(sb);

	inode_lock(inode);

	/* Currently just for extent based files */
	if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
		ret = -EOPNOTSUPP;
		goto out_mutex;
		goto out;
	}

	/* Check whether the maximum file size would be exceeded */
	if (len > inode->i_sb->s_maxbytes - inode->i_size) {
		ret = -EFBIG;
		goto out_mutex;
	/* Insert range works only on fs cluster size aligned regions. */
	if (!IS_ALIGNED(offset | len, EXT4_CLUSTER_SIZE(sb))) {
		ret = -EINVAL;
		goto out;
	}

	/* Offset must be less than i_size */
	if (offset >= inode->i_size) {
		ret = -EINVAL;
		goto out_mutex;
		goto out;
	}

	/* Check whether the maximum file size would be exceeded */
	if (len > inode->i_sb->s_maxbytes - inode->i_size) {
		ret = -EFBIG;
		goto out;
	}

	/* Wait for existing dio to complete */
@@ -5471,7 +5463,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)

	ret = file_modified(file);
	if (ret)
		goto out_mutex;
		goto out;

	/*
	 * Prevent page faults from reinstantiating pages we have released from
@@ -5481,25 +5473,24 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)

	ret = ext4_break_layouts(inode);
	if (ret)
		goto out_mmap;
		goto out_invalidate_lock;

	/*
	 * Need to round down to align start offset to page size boundary
	 * for page size > block size.
	 * Write out all dirty pages. Need to round down to align start offset
	 * to page size boundary for page size > block size.
	 */
	ioffset = round_down(offset, PAGE_SIZE);
	/* Write out all dirty pages */
	ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
			LLONG_MAX);
	start = round_down(offset, PAGE_SIZE);
	ret = filemap_write_and_wait_range(mapping, start, LLONG_MAX);
	if (ret)
		goto out_mmap;
	truncate_pagecache(inode, ioffset);
		goto out_invalidate_lock;

	truncate_pagecache(inode, start);

	credits = ext4_writepage_trans_blocks(inode);
	handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
	if (IS_ERR(handle)) {
		ret = PTR_ERR(handle);
		goto out_mmap;
		goto out_invalidate_lock;
	}
	ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);

@@ -5508,16 +5499,19 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
	EXT4_I(inode)->i_disksize += len;
	ret = ext4_mark_inode_dirty(handle, inode);
	if (ret)
		goto out_stop;
		goto out_handle;

	start_lblk = offset >> inode->i_blkbits;
	len_lblk = len >> inode->i_blkbits;

	down_write(&EXT4_I(inode)->i_data_sem);
	ext4_discard_preallocations(inode);

	path = ext4_find_extent(inode, offset_lblk, NULL, 0);
	path = ext4_find_extent(inode, start_lblk, NULL, 0);
	if (IS_ERR(path)) {
		up_write(&EXT4_I(inode)->i_data_sem);
		ret = PTR_ERR(path);
		goto out_stop;
		goto out_handle;
	}

	depth = ext_depth(inode);
@@ -5527,16 +5521,16 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
		ee_len = ext4_ext_get_actual_len(extent);

		/*
		 * If offset_lblk is not the starting block of extent, split
		 * the extent @offset_lblk
		 * If start_lblk is not the starting block of extent, split
		 * the extent @start_lblk
		 */
		if ((offset_lblk > ee_start_lblk) &&
				(offset_lblk < (ee_start_lblk + ee_len))) {
		if ((start_lblk > ee_start_lblk) &&
				(start_lblk < (ee_start_lblk + ee_len))) {
			if (ext4_ext_is_unwritten(extent))
				split_flag = EXT4_EXT_MARK_UNWRIT1 |
					EXT4_EXT_MARK_UNWRIT2;
			path = ext4_split_extent_at(handle, inode, path,
					offset_lblk, split_flag,
					start_lblk, split_flag,
					EXT4_EX_NOCACHE |
					EXT4_GET_BLOCKS_PRE_IO |
					EXT4_GET_BLOCKS_METADATA_NOFAIL);
@@ -5545,31 +5539,32 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
		if (IS_ERR(path)) {
			up_write(&EXT4_I(inode)->i_data_sem);
			ret = PTR_ERR(path);
			goto out_stop;
			goto out_handle;
		}
	}

	ext4_free_ext_path(path);
	ext4_es_remove_extent(inode, offset_lblk, EXT_MAX_BLOCKS - offset_lblk);
	ext4_es_remove_extent(inode, start_lblk, EXT_MAX_BLOCKS - start_lblk);

	/*
	 * if offset_lblk lies in a hole which is at start of file, use
	 * if start_lblk lies in a hole which is at start of file, use
	 * ee_start_lblk to shift extents
	 */
	ret = ext4_ext_shift_extents(inode, handle,
		max(ee_start_lblk, offset_lblk), len_lblk, SHIFT_RIGHT);

		max(ee_start_lblk, start_lblk), len_lblk, SHIFT_RIGHT);
	up_write(&EXT4_I(inode)->i_data_sem);
	if (ret)
		goto out_handle;

	ext4_update_inode_fsync_trans(handle, inode, 1);
	if (IS_SYNC(inode))
		ext4_handle_sync(handle);
	if (ret >= 0)
		ext4_update_inode_fsync_trans(handle, inode, 1);

out_stop:
out_handle:
	ext4_journal_stop(handle);
out_mmap:
out_invalidate_lock:
	filemap_invalidate_unlock(mapping);
out_mutex:
out:
	inode_unlock(inode);
	return ret;
}