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

Commit b6bccc97 authored by Zhang Yi's avatar Zhang Yi Committed by Greg Kroah-Hartman
Browse files

ext4: correct the error path of ext4_write_inline_data_end()



[ Upstream commit 55ce2f649b9e88111270333a8127e23f4f8f42d7 ]

Current error path of ext4_write_inline_data_end() is not correct.

Firstly, it should pass out the error value if ext4_get_inode_loc()
return fail, or else it could trigger infinite loop if we inject error
here. And then it's better to add inode to orphan list if it return fail
in ext4_journal_stop(), otherwise we could not restore inline xattr
entry after power failure. Finally, we need to reset the 'ret' value if
ext4_write_inline_data_end() return success in ext4_write_end() and
ext4_journalled_write_end(), otherwise we could not get the error return
value of ext4_journal_stop().

Signed-off-by: default avatarZhang Yi <yi.zhang@huawei.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
Link: https://lore.kernel.org/r/20210716122024.1105856-3-yi.zhang@huawei.com


Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent de4a28b7
Loading
Loading
Loading
Loading
+5 −10
Original line number Diff line number Diff line
@@ -733,18 +733,13 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
	void *kaddr;
	struct ext4_iloc iloc;

	if (unlikely(copied < len)) {
		if (!PageUptodate(page)) {
			copied = 0;
			goto out;
		}
	}
	if (unlikely(copied < len) && !PageUptodate(page))
		return 0;

	ret = ext4_get_inode_loc(inode, &iloc);
	if (ret) {
		ext4_std_error(inode->i_sb, ret);
		copied = 0;
		goto out;
		return ret;
	}

	ext4_write_lock_xattr(inode, &no_expand);
@@ -757,7 +752,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
	(void) ext4_find_inline_data_nolock(inode);

	kaddr = kmap_atomic(page);
	ext4_write_inline_data(inode, &iloc, kaddr, pos, len);
	ext4_write_inline_data(inode, &iloc, kaddr, pos, copied);
	kunmap_atomic(kaddr);
	SetPageUptodate(page);
	/* clear page dirty so that writepages wouldn't work for us. */
@@ -766,7 +761,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
	ext4_write_unlock_xattr(inode, &no_expand);
	brelse(iloc.bh);
	mark_inode_dirty(inode);
out:

	return copied;
}

+5 −2
Original line number Diff line number Diff line
@@ -1439,6 +1439,7 @@ static int ext4_write_end(struct file *file,
			goto errout;
		}
		copied = ret;
		ret = 0;
	} else
		copied = block_write_end(file, mapping, pos,
					 len, copied, page, fsdata);
@@ -1465,13 +1466,14 @@ static int ext4_write_end(struct file *file,
	if (i_size_changed || inline_data)
		ext4_mark_inode_dirty(handle, inode);

errout:
	if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
		/* if we have allocated more blocks and copied
		 * less. We will have blocks allocated outside
		 * inode->i_size. So truncate them
		 */
		ext4_orphan_add(handle, inode);
errout:

	ret2 = ext4_journal_stop(handle);
	if (!ret)
		ret = ret2;
@@ -1554,6 +1556,7 @@ static int ext4_journalled_write_end(struct file *file,
			goto errout;
		}
		copied = ret;
		ret = 0;
	} else if (unlikely(copied < len) && !PageUptodate(page)) {
		copied = 0;
		ext4_journalled_zero_new_buffers(handle, page, from, to);
@@ -1583,6 +1586,7 @@ static int ext4_journalled_write_end(struct file *file,
			ret = ret2;
	}

errout:
	if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
		/* if we have allocated more blocks and copied
		 * less. We will have blocks allocated outside
@@ -1590,7 +1594,6 @@ static int ext4_journalled_write_end(struct file *file,
		 */
		ext4_orphan_add(handle, inode);

errout:
	ret2 = ext4_journal_stop(handle);
	if (!ret)
		ret = ret2;